home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Game / board / Saga.lha / Saga / source / system.c < prev   
C/C++ Source or Header  |  2004-09-01  |  179KB  |  4,207 lines

  1. /* Known bugs:
  2.  memory leak in createcounters()/destroycounters(), not sure why.
  3.  
  4. 1. INCLUDES ----------------------------------------------------------- */
  5.  
  6. #include <exec/exec.h>
  7. #include <intuition/intuition.h>
  8. #include <utility/tagitem.h>
  9. #include <graphics/gfx.h>
  10. #include <libraries/gadtools.h>    // struct NewMenu
  11. #include <devices/timer.h>         // struct timeval
  12. #include <dos/dosextens.h>         // struct Process
  13. #include <libraries/asl.h>         // ASL_FileRequest
  14. #include <dos/dostags.h>           // SYS_Output
  15. #include <dos/datetime.h>          // struct DateTime
  16. #include <libraries/locale.h>
  17. #define OLD_GRAPHICS_GFXMACROS_H
  18. #include <graphics/gfxmacros.h>
  19. #include <hardware/custom.h>
  20. #include <hardware/dmabits.h>
  21.  
  22. #include <ctype.h>                 // toupper()
  23. #include <stdlib.h>                /* EXIT_SUCCESS, etc. */
  24. #include <stdio.h>
  25. #include <string.h>                // strcpy(), etc.
  26. #define ASSERT
  27. #include <assert.h>
  28.  
  29. #include "saga.h"
  30.  
  31. #define CATCOMP_NUMBERS
  32. #define CATCOMP_CODE
  33. #define CATCOMP_BLOCK
  34.  
  35. #include <clib/exec_protos.h>      // OpenLibrary(), etc.
  36. #include <clib/intuition_protos.h> // Object, etc.
  37. #include <clib/graphics_protos.h>
  38. #include <clib/dos_protos.h>
  39. #include <clib/gadtools_protos.h>
  40. #include <clib/timer_protos.h>
  41. #include <clib/locale_protos.h>    // GetCatalogStr()
  42. #include <clib/asl_protos.h>
  43. #include <clib/diskfont_protos.h>
  44. #include "saga_strings.h"
  45.  
  46. // #define ASSERT
  47.  
  48. // 2. DEFINES ------------------------------------------------------------
  49.  
  50. #define QUICKMOVES
  51. // #define EXTRAVERBOSE
  52.  
  53. // version-dependent constants
  54. #define TITLEBAR         "Saga 1.5"
  55. #define VERSION          "$VER: Saga 1.5 (2.9.2004)"
  56. #define RELEASEDATE      "02-Sep-04"
  57. #define COPYRIGHT        "© 2002-2004 Amigan Software"
  58.  
  59. #define CONFIGLENGTH    23
  60. #define SAVELENGTH     577
  61.  
  62. #define SCOREDISTANCE   13
  63. #define MESSAGEY       (TBSIZE + 473)
  64.  
  65. #define ONE_BILLION      1000000000
  66.  
  67. // scancodes
  68. #define SCAN_Q          16
  69. #define ESCAPE          69
  70. #define SCAN_RIGHT      78
  71. #define SCAN_LEFT       79
  72. #define SCAN_F1         80
  73. #define SCAN_F2         81
  74. #define SCAN_F3         82
  75. #define SCAN_F4         83
  76. #define SCAN_F5         84
  77. #define SCAN_F6         85
  78. #define HELP            95
  79. #define FIRSTQUALIFIER  96
  80. #define LASTQUALIFIER  103
  81. #define KEYUP          128 /* key release */
  82.  
  83. #define HERO_STRENGTH    5
  84. #define HERO_MOVES       4
  85.  
  86. STRPTR trueheroname[HEROES + 1] =
  87. {   "Beowulf",
  88.     "Brunhild",
  89.     "Egil",
  90.     "Ragnar",
  91.     "Siegfried",
  92.     "Starkad"
  93. }, cycleheroname[HEROES + 1] =
  94. {   "  Beowulf:",
  95.     " Brunhild:",
  96.     "     Egil:",
  97.     "   Ragnar:",
  98.     "Siegfried:",
  99.     "  Starkad:"
  100. };
  101.  
  102. #define MN_PROJECT           0
  103. #define MN_SETTINGS          1
  104. #define MN_HELP              2
  105. #define IN_NEW               0
  106. #define IN_OPEN              1
  107. #define IN_SAVE              3
  108. #define IN_SAVEAS            4
  109. #define IN_QUIT              6
  110. #define IN_SHOW_TITLEBAR     0
  111. #define IN_GAME_SUMMARY      0
  112. #define IN_HELP_1            2
  113. #define IN_HELP_2            3
  114. #define IN_HELP_3            4
  115. #define IN_HELP_4            5
  116. #define IN_ABOUT             7
  117.  
  118. #define INDEX_PROJECT        0
  119. #define INDEX_NEW            1
  120. #define INDEX_OPEN           2
  121. #define INDEX_SAVE           4
  122. #define INDEX_SAVE_AS        5
  123. #define INDEX_QUIT           7
  124. #define INDEX_SETTINGS       8
  125. #define INDEX_SHOW_TITLEBAR  9
  126. #define INDEX_HELP          10
  127. #define INDEX_GAME_SUMMARY  11
  128. #define INDEX_HELP_1        13
  129. #define INDEX_HELP_2        14
  130. #define INDEX_HELP_3        15
  131. #define INDEX_HELP_4        16
  132. #define INDEX_ABOUT         18
  133.  
  134. #define SUMMARYWIDTH       378
  135. #define SUMMARYHEIGHT       42 // +10 per extra line (heading is already factored in)
  136.  
  137. #define ABOUTLINES           3
  138. #define MENUENTRIES         19 // counting from 0
  139.  
  140. // 3. EXPORTED VARIABLES -------------------------------------------------
  141.  
  142. EXPORT struct GfxBase*       GfxBase                    = NULL;
  143. EXPORT struct GadToolsBase*  GadToolsBase               = NULL;
  144. EXPORT struct IntuitionBase* IntuitionBase              = NULL;
  145. EXPORT struct LocaleBase*    LocaleBase                 = NULL;
  146. EXPORT struct Library*       TimerBase                  = NULL;
  147. EXPORT struct ASLBase*       ASLBase                    = NULL;
  148. EXPORT struct DiskFontBase*  DiskFontBase               = NULL;
  149.  
  150. EXPORT STRPTR                monstertypes[8];
  151. EXPORT SLONG                 faxirides,
  152.                              monsters,
  153.                              treasures;
  154. EXPORT TEXT                  onekey[ONEKEYS + 1]        = {'Y', 'N', 'W', 'R', 'T', 'G', 'L'};
  155. EXPORT UWORD                 DisplayDepth               = DEPTH;
  156. EXPORT TEXT                  saystring[256 + 1],
  157.                              saystring2[256 + 1],
  158.                              numberstring[13 + 1],
  159.                              label[17 + 1][40 + 1],
  160.                              line[2][MAXLINES + 1][80 + 1];
  161. EXPORT FLAG                  advanced                   = TRUE;
  162. EXPORT ULONG                 DisplayWidth               = SCREENXPIXEL,
  163.                              DisplayHeight              = SCREENYPIXEL;
  164. EXPORT struct Window        *MainWindowPtr              = NULL,
  165.                             *HelpWindowPtr              = NULL,
  166.                             *InfoWindowPtr              = NULL;
  167. EXPORT struct LocaleInfo     li;
  168. EXPORT struct Screen*        ScreenPtr                  = NULL;
  169. EXPORT struct ScreenBuffer*  ScreenBuf[2]               = {NULL, NULL};
  170.  
  171. // 4. IMPORTED VARIABLES -------------------------------------------------
  172.  
  173. IMPORT struct ExecBase*      SysBase;
  174. IMPORT struct Custom         custom;
  175.  
  176. IMPORT struct WorldStruct    world[36 + 30];
  177. IMPORT struct RuneStruct     rune[RUNES + 1];
  178. IMPORT struct TreasureStruct treasure[TREASURES + 1];
  179. IMPORT struct HeroStruct     hero[HEROES + 1];
  180. IMPORT struct JarlStruct     jarl[JARLS + 1];
  181. IMPORT struct SordStruct     sord[SORDS + 1];
  182. IMPORT struct MonsterStruct  monster[MONSTERS + 1];
  183.  
  184. // 5. MODULE VARIABLES ---------------------------------------------------
  185.  
  186. MODULE STRPTR                CycleOptions[4];
  187. MODULE WORD                  speed                      = 4;
  188. MODULE UBYTE                 IOBuffer[600];
  189. MODULE APTR                  OldWindowPtr               = NULL;
  190. MODULE SLONG                 turn;
  191. MODULE FLAG                  aga                        = FALSE,
  192.                              dbuf                       = FALSE,
  193.                              cliload                    = FALSE,
  194.                              nodbuf                     = FALSE,
  195.                              saveconfig                 = FALSE,
  196.                              titlebar                   = TRUE,
  197.                              gameover,
  198.                              loaded;
  199. MODULE TEXT                  abouttitle[80 + 1],
  200.                              titlestring[80 + 1],
  201.                              pathname[256 + 1];
  202. MODULE ULONG                 DisplayID                  = HIRES_KEY | PAL_MONITOR_ID | LACE;
  203. MODULE struct RDArgs*        ArgsPtr                    = NULL;
  204. MODULE struct FileRequester* ASLRqPtr                   = NULL;
  205. MODULE struct Process*       ProcessPtr                 = NULL;
  206. MODULE struct Menu*          MenuPtr                    = NULL;
  207. MODULE struct VisualInfo*    VisualInfoPtr              = NULL;
  208. MODULE struct TextFont*      FontPtr                    = NULL;
  209. MODULE struct Gadget        *SpeedGadgetPtr             = NULL,
  210.                             *CycleGadgetPtr[HEROES + 1] = {NULL, NULL, NULL, NULL, NULL, NULL},
  211.                             *AdvancedGadgetPtr          = NULL,
  212.                             *GListPtr                   = NULL,
  213.                             *PrevGadgetPtr              = NULL;
  214. MODULE SLONG                 tickspeed[6 + 1]           = {2, 4, 8, 12, 16, 20, -1};
  215.  
  216. // 6. MODULE STRUCTURES --------------------------------------------------
  217.  
  218. MODULE struct
  219. {   UBYTE red, green, blue;
  220. } taxcolours[10 + 1] =
  221. {   {  0,  5,  0 }, // tax  0 (unused)
  222.     {  1,  6,  1 }, // tax  1 (unused)
  223.     {  2,  7,  2 }, // tax  2
  224.     {  3,  8,  3 }, // tax  3
  225.     {  4,  9,  4 }, // tax  4
  226.     {  5, 10,  5 }, // tax  5
  227.     {  6, 11,  6 }, // tax  6
  228.     {  7, 12,  7 }, // tax  7
  229.     {  8, 13,  8 }, // tax  8
  230.     {  9, 14,  9 }, // tax  9
  231.     { 10, 15, 10 }  // tax 10
  232. };
  233.  
  234. MODULE struct
  235. {   WORD x, y;
  236.     TEXT text[80 + 1];
  237. } about[ABOUTLINES + 1] =
  238. {   {65, 14},
  239.     {65, 24},
  240.     {65, 44},
  241.     {65, 54}
  242. };
  243.  
  244. MODULE struct NewMenu NewMenu[MENUENTRIES + 1] =
  245. {   { NM_TITLE, "",           0 , 0,                    0, 0}, //  0
  246.     {  NM_ITEM, "",          "" , 0,                    0, 0}, //  1
  247.     {  NM_ITEM, "",          "" , 0,                    0, 0}, //  2
  248.     {  NM_ITEM, NM_BARLABEL,  0 , 0,                    0, 0}, //  3
  249.     {  NM_ITEM, "",          "" , 0,                    0, 0}, //  4
  250.     {  NM_ITEM, "",          "" , 0,                    0, 0}, //  5
  251.     {  NM_ITEM, NM_BARLABEL,  0 , 0,                    0, 0}, //  6
  252.     {  NM_ITEM, "",          "" , 0,                    0, 0}, //  7
  253.     { NM_TITLE, "",           0 , 0,                    0, 0}, //  8
  254.     {  NM_ITEM, "",          "",  CHECKIT | MENUTOGGLE, 0, 0}, //  9
  255.     { NM_TITLE, "",           0 , 0,                    0, 0}, // 10
  256.     {  NM_ITEM, "",          "" , 0,                    0, 0}, // 11 (game summary)
  257.     {  NM_ITEM, NM_BARLABEL,  0 , 0,                    0, 0}, // 12 (------------)
  258.     {  NM_ITEM, "",          "1", 0,                    0, 0}, // 13 (help 1)
  259.     {  NM_ITEM, "",          "2", 0,                    0, 0}, // 14 (help 2)
  260.     {  NM_ITEM, "",          "3", 0,                    0, 0}, // 15 (help 3)
  261.     {  NM_ITEM, "",          "4", 0,                    0, 0}, // 16 (help 4)
  262.     {  NM_ITEM, NM_BARLABEL,  0 , 0,                    0, 0}, // 17 (------------)
  263.     {  NM_ITEM, "",          "?", 0,                    0, 0}, // 18 (about)
  264.     {   NM_END, NULL,         0 , 0,                    0, 0}  // 19
  265. };
  266.  
  267. // These are better to not be allocated on the stack
  268. MODULE ULONG table1[] = {(8L << 16) + 0,
  269.     0x00000000, 0x00000000, 0x00000000, //   0 (BLACK)
  270.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, //   1 (WHITE)
  271.     0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, //   2 (LIGHTGREY)
  272.     0x99999999, 0x99999999, 0x99999999, //   3 (MEDIUMGREY)
  273.     0x66666666, 0x66666666, 0x66666666, //   4 (DARKGREY)
  274.     0x66666666, 0xFFFFFFFF, 0x66666666, //   5 (GREEN)
  275.     0x88888888, 0x88888888, 0xFFFFFFFF, //   6 (BLUE)
  276.     0x00000000, 0x00000000, 0x00000000, //   7
  277.     0};
  278. MODULE ULONG table2[] = {(68L << 16) + 74,
  279.     0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, //  74
  280.     0xFFFFFFFF, 0xCCCCCCCC, 0x00000000, //  75
  281.     0xFFFFFFFF, 0x99999999, 0x00000000, //  76
  282.     0xFFFFFFFF, 0x66666666, 0x00000000, //  77
  283.     0xFFFFFFFF, 0x33333333, 0x00000000, //  78
  284.     0xFFFFFFFF, 0x00000000, 0x00000000, //  79
  285.     0x00000000, 0x00000000, 0x00000000, //  80
  286.     0x00000000, 0x00000000, 0x99999999, //  81
  287.     0x00000000, 0x00000000, 0x00000000, //  82
  288.     0x00000000, 0x00000000, 0x99999999, //  83
  289.     0x00000000, 0x00000000, 0x00000000, //  84
  290.     0x00000000, 0x00000000, 0x99999999, //  85
  291.     0xFFFFFFFF, 0xBBBBBBBB, 0x33333333, //  86 (ORANGE)
  292.     0xFFFFFFFF, 0x88888888, 0xFFFFFFFF, //  87 (PURPLE)
  293.     0xFFFFFFFF, 0x55555555, 0x55555555, //  88 (RED)
  294.     0x00000000, 0x00000000, 0x00000000, //  89
  295.     0x00000000, 0x00000000, 0x00000000, //  90
  296.     0x00000000, 0x00000000, 0x00000000, //  91
  297.     0x00000000, 0x00000000, 0xFFFFFFFF, //  92
  298.     0x00000000, 0x00000000, 0xFFFFFFFF, //  93
  299.     0x10101010, 0x14141414, 0xFFFFFFFF, //  94
  300.     0x1F1F1F1F, 0x23232323, 0xFFFFFFFF, //  95
  301.     0x2E2E2E2E, 0x32323232, 0xFFFFFFFF, //  96
  302.     0x3D3D3D3D, 0x41414141, 0xFFFFFFFF, //  97
  303.     0x4C4C4C4C, 0x4F4F4F4F, 0xFFFFFFFF, //  98
  304.     0x5B5B5B5B, 0x5E5E5E5E, 0xFFFFFFFF, //  99
  305.     0x6A6A6A6A, 0x6D6D6D6D, 0xFFFFFFFF, // 100
  306.     0x79797979, 0x7C7C7C7C, 0xFFFFFFFF, // 101
  307.     0x87878787, 0x89898989, 0xFFFFFFFF, // 102
  308.     0x96969696, 0x98989898, 0xFFFFFFFF, // 103
  309.     0xA5A5A5A5, 0xA7A7A7A7, 0xFFFFFFFF, // 104
  310.     0xB4B4B4B4, 0xB6B6B6B6, 0xFFFFFFFF, // 105
  311.     0xC3C3C3C3, 0xC4C4C4C4, 0xFFFFFFFF, // 106
  312.     0xD2D2D2D2, 0xD3D3D3D3, 0xFFFFFFFF, // 107
  313.     0xE1E1E1E1, 0xE2E2E2E2, 0xFFFFFFFF, // 108
  314.     0xF0F0F0F0, 0xF1F1F1F1, 0xFFFFFFFF, // 109
  315.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 110
  316.     0x00000000, 0x00000000, 0xFFFFFFFF, // 111
  317.     0x00000000, 0x88888888, 0xFFFFFFFF, // 112
  318.     0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, // 113
  319.     0x99999999, 0x99999999, 0xFFFFFFFF, // 114
  320.     0x00000000, 0x00000000, 0x00000000, // 115
  321.     0x99999999, 0xFFFFFFFF, 0x99999999, // 116
  322.     0x00000000, 0x00000000, 0x00000000, // 117
  323.     0xFFFFFFFF, 0xCCCCCCCC, 0x99999999, // 118
  324.     0x00000000, 0x00000000, 0x00000000, // 119
  325.     0xFFFFFFFF, 0x99999999, 0xFFFFFFFF, // 120
  326.     0x00000000, 0x00000000, 0x00000000, // 121
  327.     0xFFFFFFFF, 0xFFFFFFFF, 0x99999999, // 122
  328.     0x00000000, 0x00000000, 0x00000000, // 123
  329.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 124
  330.     0x00000000, 0x00000000, 0x00000000, // 125
  331.     0xFFFFFFFF, 0x00000000, 0x00000000, // 126 (boing red)
  332.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, // 127 (boing white)
  333.     0x44444444, 0x44444444, 0x44444444, // 128
  334.     0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, // 129
  335.     0x66666666, 0x66666666, 0x66666666, // 130
  336.     0x77777777, 0x77777777, 0x77777777, // 131
  337.     0x88888888, 0x88888888, 0x88888888, // 132
  338.     0x99999999, 0x99999999, 0x99999999, // 133
  339.     0x55555555, 0x55555555, 0x55555555, // 134
  340.     0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB, // 135
  341.     0xFFFFFFFF, 0xCCCCCCCC, 0x66666666, // 136 (Beowulf   - orange)
  342.     0xFFFFFFFF, 0x66666666, 0x66666666, // 137 (Brunhild  - red)
  343.     0xFFFFFFFF, 0xFFFFFFFF, 0x33333333, // 138 (Egil      - yellow)
  344.     0x66666666, 0xFFFFFFFF, 0xFFFFFFFF, // 139 (Ragnar    - cyan)
  345.     0xAAAAAAAA, 0xAAAAAAAA, 0xFFFFFFFF, // 140 (Siegfried - light blue)
  346.     0xFFFFFFFF, 0x66666666, 0xFFFFFFFF, // 141 (Starkad   - purple)
  347. 0};
  348.  
  349. MODULE struct NewGadget SpeedGadget =
  350. {   300, TBSIZE + 296,
  351.     128, 13,
  352.     "",
  353.     NULL,
  354.     NULL,
  355.     NULL,
  356.     NULL,
  357.     NULL
  358. }, AdvancedGadget =
  359. {   300, TBSIZE + 320,
  360.     0, 0,
  361.     "",
  362.     NULL,
  363.     NULL,
  364.     NULL,
  365.     NULL,
  366.     NULL
  367. }, CycleGadget[HEROES + 1] = {
  368. {   300, TBSIZE + 200,
  369.     128, 13,
  370.     NULL,
  371.     NULL,
  372.     NULL,
  373.     NULL,
  374.     NULL,
  375.     NULL
  376. },
  377. {   300, TBSIZE + 213,
  378.     128, 13,
  379.     NULL,
  380.     NULL,
  381.     NULL,
  382.     NULL,
  383.     NULL,
  384.     NULL
  385. },
  386. {   300, TBSIZE + 226,
  387.     128, 13,
  388.     NULL,
  389.     NULL,
  390.     NULL,
  391.     NULL,
  392.     NULL,
  393.     NULL
  394. },
  395. {   300, TBSIZE + 239,
  396.     128, 13,
  397.     NULL,
  398.     NULL,
  399.     NULL,
  400.     NULL,
  401.     NULL,
  402.     NULL
  403. },
  404. {   300, TBSIZE + 252,
  405.     128, 13,
  406.     NULL,
  407.     NULL,
  408.     NULL,
  409.     NULL,
  410.     NULL,
  411.     NULL
  412. },
  413. {   300, TBSIZE + 265,
  414.     128, 13,
  415.     NULL,
  416.     NULL,
  417.     NULL,
  418.     NULL,
  419.     NULL,
  420.     NULL
  421. }
  422. };
  423.  
  424. MODULE SLONG cycleheropos[HEROES + 1] =
  425. {   2,
  426.     3,
  427.     5,
  428.     3,
  429.     0,
  430.     3
  431. };
  432.  
  433. MODULE struct
  434. {   UBYTE red, green, blue;
  435. } herocolour[HEROES + 1] =
  436. { { 15,  12,   6}, // orange
  437.   { 15,   6,   6}, // red
  438.   { 15,  15,   3}, // yellow
  439.   {  6,  15,  15}, // cyan
  440.   { 10,  10,  15}, // light blue
  441.   { 15,   6,  15}  // purple
  442. };
  443.  
  444. // 7. MODULE FUNCTIONS ---------------------------------------------------
  445.  
  446. MODULE void gameloop(void);
  447. MODULE void newgame(void);
  448. MODULE void clearkybd(void);
  449. MODULE void titlescreen(void);
  450. MODULE void helpabout(void);
  451. MODULE void resettime(void);
  452. MODULE FLAG loadgame(FLAG aslwindow);
  453. MODULE void savegame(FLAG saveas);
  454. MODULE SLONG checkcountry(WORD mousex, WORD mousey);
  455. MODULE void infowindow(SLONG countertype, SLONG whichcounter);
  456. MODULE void flash(SLONG country);
  457. MODULE void summarywindow(void);
  458. MODULE void cycle(SLONG whichhero, UWORD qual);
  459. MODULE void docwindow(SLONG number);
  460. MODULE void infoloop(void);
  461.  
  462. // 8. CODE ---------------------------------------------------------------
  463.  
  464. int main(int argc, char** argv)
  465. {   struct DisplayInfo          QueryInfo;
  466.     struct TextAttr WormWars8 =
  467.     {   (STRPTR) "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  468.     },              Topaz8 =
  469.     {   (STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
  470.     };
  471.     struct DateTime             DateTime;
  472.     struct ScreenModeRequester* smr;
  473.     BPTR                        FileHandle /* = NULL */ ;
  474.     FLAG                        ok;
  475.     TEXT                        datestring[LEN_DATSTRING],
  476.                                 weekdaystring[LEN_DATSTRING],
  477.                                 tempstring[1 + 1],
  478.                                 smrstring[80 + 1],
  479.                                 supergels[2];
  480.     SLONG                       whichcountry, whichhero,
  481.                                 args[7 + 1] = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
  482.     ULONG                       fonttag,
  483.                                 publictag;
  484.     UWORD                       Pens[13] =
  485.     {   BLACK,     /* DETAILPEN            text in title bar */
  486.         WHITE,     /* BLOCKPEN             fill title bar */
  487.         BLACK,     /* TEXTPEN              regular text on BACKGROUNDPEN */
  488.         LIGHTGREY, /* SHINEPEN             bright edge */
  489.         DARKGREY,  /* SHADOWPEN            dark edge */
  490.         BLUE,      /* FILLPEN              filling active window borders
  491.                                            and selected gadgets */
  492.         BLACK,     /* FILLTEXTPEN          text rendered over FILLPEN */
  493.         MEDIUMGREY,/* BACKGROUNDPEN        background colour */
  494.         ORANGE,    /* HIGHLIGHTTEXTPEN     highlighted text on BACKGROUNDPEN
  495.                                            and used against BLOCKPEN in ASL
  496.                                            save requesters */
  497.         BLACK,     /* BARDETAILPEN         text/detail in screen-bar/menus */
  498.         WHITE,     /* BARBLOCKPEN          screen-bar/menus fill */
  499.         BLACK,     /* BARTRIMPEN           trim under screen-bar */
  500.         (UWORD) ~0 /* and used against BLOCKPEN in ASL save requesters */
  501.     };
  502.  
  503. /* Colour allocations are as follows:
  504.     colours 0-6 are used by the game itself.
  505.     colour 7 is the black of the map.
  506.     colours 8-43 are map land colours, except that
  507.     colours 17-19 are mouse pointer colours.
  508.     colours 44-73 are map sea colours.
  509.     colours 74-79 are used for the Amigan Software logo.
  510.     colour 80 is Scandian coastline.
  511.     colour 81 is Scandian sea.
  512.     colour 82 is Pictish coastline.
  513.     colour 83 is Pictish sea.
  514.     colour 84 is Hebridean coastline.
  515.     colour 85 is Hebridean sea.
  516.     colours 86-88 are used by the game itself.
  517.     colour 89 is Suder Gotland land (replacement for colour 17).
  518.     colour 90 is Juteland land (replacement for colour 18).
  519.     colour 91 is Scandian land (replacement for colour 19).
  520.     colour 92 is used for the Amigan Software logo.
  521.     colours 93-110 are used for the Saga logo.
  522.     colours 111-113 are used for the Amigan Software logo.
  523.     colours 114-125 are used for counter colours:
  524.      114/115: heroes
  525.      116/117: jarls
  526.      118/119: monsters
  527.      120/121: swords
  528.      122/123: treasures
  529.      124/125: selected counters
  530.     colours 126-127 are colours for the chequered boing ball animation.
  531.     colours 128-135 are for the background.
  532.     colours 136-141 are hero colours.
  533.  
  534.     Start of program.
  535.  
  536.     version embedding into executable */
  537.     if (0) /* that is, never */
  538.     {   Printf("%s\n", VERSION);
  539.     }
  540.  
  541.     // It would be good to seed the random number generator with the time.
  542.  
  543.     // before the first possible point of failure
  544.     init_counters();
  545.     for (whichcountry = 0; whichcountry <= 65; whichcountry++)
  546.     {   world[whichcountry].hero = -1;
  547.     }
  548.     pathname[0] = 0;
  549.  
  550.     if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 39L)))
  551.     {   strcpy(saystring, "Saga: Can't open intuition.library V39+!)\n");
  552.         Write(Output(), saystring, strlen(saystring));
  553.         cleanexit(EXIT_FAILURE);
  554.     }
  555.  
  556.     ProcessPtr = (struct Process *) FindTask(NULL);
  557.  
  558.     if (SysBase->LibNode.lib_Version < 36L)
  559.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open exec.library V36+!\0", 24);
  560.         cleanexit(EXIT_FAILURE);
  561.     }
  562.  
  563.     // From this point onwards, we can be sure we have Kickstart 2.0+...
  564.  
  565.     if (GetVar("cybergfx/supergels", supergels, 2, NULL) == 1)
  566.     {   if (supergels[0] == '1')
  567.         {   Printf("Saga: ENV:cybergfx/supergels must be cleared to 0 before playing!\n");
  568.             cleanexit(EXIT_FAILURE);
  569.     }   }
  570.  
  571.     /* NOTE FOR TRANSLATORS:
  572.     MSG_CHAR_FOO messages are single-character strings which are the
  573.     first letter of the relevant word. MSG_UNCHAR_FOO messages are the
  574.     rest of the word. Eg. in English, MSG_CHAR_GLORY is "G" and
  575.     MSG_UNCHAR_GLORY is "lory". They must each be different among their
  576.     'set' (yes/no, glory/luck, restart/transfer/withdraw). */
  577.  
  578.     li.li_Catalog = NULL;
  579.     if (LocaleBase = (struct LocaleBase *) OpenLibrary("locale.library", 38))
  580.     {   li.li_LocaleBase   = LocaleBase;
  581.         li.li_Catalog      = OpenCatalog(NULL, "Saga.catalog", TAG_DONE);
  582.     }
  583.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_YES,      "Y"));
  584.     onekey[ONEKEY_YES]      = tempstring[0];
  585.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_NO,       "N"));
  586.     onekey[ONEKEY_NO]       = tempstring[0];
  587.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_WITHDRAW, "W"));
  588.     onekey[ONEKEY_WITHDRAW] = tempstring[0];
  589.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_RESTART,  "R"));
  590.     onekey[ONEKEY_RESTART]  = tempstring[0];
  591.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_TRANSFER, "T"));
  592.     onekey[ONEKEY_TRANSFER] = tempstring[0];
  593.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_GLORY,    "G"));
  594.     onekey[ONEKEY_GLORY]    = tempstring[0];
  595.     strcpy(tempstring, GetCatalogStr(li.li_Catalog, MSG_CHAR_LUCK,     "L"));
  596.     onekey[ONEKEY_LUCK]     = tempstring[0];
  597.     CycleOptions[0] = GetCatalogStr(li.li_Catalog, MSG_GADGET_NONE, "None");
  598.     CycleOptions[1] = GetCatalogStr(li.li_Catalog, MSG_HUMAN, "Human");
  599.     CycleOptions[2] = "Amiga";
  600.     CycleOptions[3] = NULL;
  601.     strcpy(abouttitle, GetCatalogStr(li.li_Catalog, MSG_ABOUT, "About"));
  602.     strcat(abouttitle, " Saga");
  603.     strcpy(about[0].text, TITLEBAR);
  604.     about[1].text[0] = 0;
  605.     DateTime.dat_Format          = FORMAT_DOS;
  606.     DateTime.dat_Flags           = NULL;
  607.     DateTime.dat_StrDate         = RELEASEDATE;
  608.     DateTime.dat_StrDay          = NULL;
  609.     DateTime.dat_StrTime         = NULL;
  610.     DateTime.dat_Stamp.ds_Minute = 0;
  611.     DateTime.dat_Stamp.ds_Tick   = 0;
  612.     if (StrToDate(&DateTime))
  613.     {   // DateTime.dat_Stamp is now filled
  614.         DateTime.dat_Format  = FORMAT_DEF;
  615.         DateTime.dat_Flags   = NULL;
  616.         DateTime.dat_StrDate = datestring;
  617.         DateTime.dat_StrDay  = weekdaystring;
  618.         DateTime.dat_StrTime = NULL;
  619.         if (DateToStr(&DateTime))
  620.         {   strcpy(about[1].text, weekdaystring);
  621.             strcat(about[1].text, " ");
  622.             strcat(about[1].text, datestring);
  623.     }   }
  624.     strcpy(about[2].text, COPYRIGHT);
  625.     strcpy(about[3].text, GetCatalogStr(li.li_Catalog, MSG_BY, "By"));
  626.     strcat(about[3].text, " James R. Jacobs");
  627.     monstertypes[0] = GetCatalogStr(li.li_Catalog, MSG_DRAGON, "Dragon");
  628.     monstertypes[1] = GetCatalogStr(li.li_Catalog, MSG_DROW  , "Drow"  );
  629.     monstertypes[2] = GetCatalogStr(li.li_Catalog, MSG_GIANT , "Giant" );
  630.     monstertypes[3] = GetCatalogStr(li.li_Catalog, MSG_GHOST , "Ghost" );
  631.     monstertypes[4] = GetCatalogStr(li.li_Catalog, MSG_TROLL , "Troll" );
  632.     monstertypes[5] = GetCatalogStr(li.li_Catalog, MSG_WITCH , "Witch" );
  633.     monstertypes[6] = GetCatalogStr(li.li_Catalog, MSG_HYDRA , "Hydra" );
  634.     monstertypes[7] = GetCatalogStr(li.li_Catalog, MSG_SEA_SERPENT, "Sea Serpent");
  635.     rune[0].desc = GetCatalogStr(li.li_Catalog, MSG_THE_GODS, "rune of the gods");
  636.     rune[1].desc = GetCatalogStr(li.li_Catalog, MSG_TIME    , "rune of time"    );
  637.     rune[2].desc = GetCatalogStr(li.li_Catalog, MSG_PROPERTY, "rune of property");
  638.     rune[3].desc = GetCatalogStr(li.li_Catalog, MSG_HEALING , "rune of healing" );
  639.     rune[4].desc = GetCatalogStr(li.li_Catalog, MSG_FURY    , "rune of fury"    );
  640.     rune[5].desc = GetCatalogStr(li.li_Catalog, MSG_THE_SUN , "rune of the sun" );
  641.     for (whichcountry = 36; whichcountry <= 39; whichcountry++)
  642.     {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_ATLANTIC_OCEAN , "Atlantic Ocean" );
  643.     }
  644.     for (whichcountry = 40; whichcountry <= 42; whichcountry++)
  645.     {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_IRISH_SEA      , "Irish Sea"      );
  646.     }
  647.     for (whichcountry = 43; whichcountry <= 44; whichcountry++)
  648.     {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_ENGLISH_CHANNEL, "English Channel");
  649.     }
  650.     for (whichcountry = 45; whichcountry <= 62; whichcountry++)
  651.     {   if (whichcountry < 47 || whichcountry > 48)
  652.         {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_NORTH_SEA  , "North Sea"      );
  653.     }   }
  654.     for (whichcountry = 63; whichcountry <= 65; whichcountry++)
  655.     {   world[whichcountry].name = GetCatalogStr(li.li_Catalog, MSG_BALTIC_SEA, "Baltic Sea");
  656.     }
  657.     treasure[BROSUNGNECKLACE].name           = GetCatalogStr(li.li_Catalog, MSG_BROSUNG_NECKLACE     , "Brosung Necklace");
  658.     treasure[MAGICSHIRT].name                = GetCatalogStr(li.li_Catalog, MSG_MAGIC_SHIRT          , "Magic Shirt"     );
  659.     treasure[MAILCOAT].name                  = GetCatalogStr(li.li_Catalog, MSG_MAIL_COAT            , "Mail Coat"       );
  660.     treasure[HEALINGPOTION].name             = GetCatalogStr(li.li_Catalog, MSG_HEALING_POTION       , "Healing Potion"  );
  661.     treasure[TELEPORTSCROLL].name            = GetCatalogStr(li.li_Catalog, MSG_TELEPORT_SCROLL      , "Teleport Scroll" );
  662.  
  663.     NewMenu[INDEX_PROJECT].nm_Label          = GetCatalogStr(li.li_Catalog, MSG_PROJECT              , "Project"         );
  664.     NewMenu[INDEX_NEW].nm_Label              = GetCatalogStr(li.li_Catalog, MSG_NEW                  , "New"             );
  665.     NewMenu[INDEX_NEW].nm_CommKey            = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_NEW         , "N"               );
  666.     NewMenu[INDEX_OPEN].nm_Label             = GetCatalogStr(li.li_Catalog, MSG_OPEN                 , "Open..."         );
  667.     NewMenu[INDEX_OPEN].nm_CommKey           = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_OPEN        , "O"               );
  668.     NewMenu[INDEX_SAVE].nm_Label             = GetCatalogStr(li.li_Catalog, MSG_SAVE                 , "Save"            );
  669.     NewMenu[INDEX_SAVE].nm_CommKey           = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_SAVE        , "S"               );
  670.     NewMenu[INDEX_SAVE_AS].nm_Label          = GetCatalogStr(li.li_Catalog, MSG_SAVE_AS              , "Save As..."      );
  671.     NewMenu[INDEX_SAVE_AS].nm_CommKey        = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_SAVE_AS     , "A"               );
  672.     NewMenu[INDEX_QUIT].nm_Label             = GetCatalogStr(li.li_Catalog, MSG_QUIT                 , "Quit"            );
  673.     NewMenu[INDEX_QUIT].nm_CommKey           = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_QUIT        , "Q"               );
  674.     NewMenu[INDEX_SETTINGS].nm_Label         = GetCatalogStr(li.li_Catalog, MSG_SETTINGS             , "Settings"        );
  675.     NewMenu[INDEX_SHOW_TITLEBAR].nm_Label    = GetCatalogStr(li.li_Catalog, MSG_SHOW_TITLEBAR        , "Show Titlebar?"  );
  676.     NewMenu[INDEX_SHOW_TITLEBAR].nm_CommKey  = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_S_T_B       , "B"               );
  677.     NewMenu[INDEX_HELP].nm_Label             = GetCatalogStr(li.li_Catalog, MSG_HELP                 , "Help"            );
  678.     NewMenu[INDEX_GAME_SUMMARY].nm_Label     = GetCatalogStr(li.li_Catalog, MSG_GAME_SUMMARY2        , "Game Summary..." );
  679.     NewMenu[INDEX_GAME_SUMMARY].nm_CommKey   = GetCatalogStr(li.li_Catalog, MSG_SHORTCUT_GAME_SUMMARY, "G"               );
  680.     NewMenu[INDEX_HELP_1].nm_Label           = GetCatalogStr(li.li_Catalog, MSG_HELP_1               , "Runes..."        );
  681.     NewMenu[INDEX_HELP_2].nm_Label           = GetCatalogStr(li.li_Catalog, MSG_HELP_2               , "Spells..."       );
  682.     NewMenu[INDEX_HELP_3].nm_Label           = GetCatalogStr(li.li_Catalog, MSG_HELP_3               , "Swords..."       );
  683.     NewMenu[INDEX_HELP_4].nm_Label           = GetCatalogStr(li.li_Catalog, MSG_HELP_4               , "Treasures..."    );
  684.     NewMenu[INDEX_ABOUT].nm_Label            = GetCatalogStr(li.li_Catalog, MSG_ABOUT2               , "About..."        );
  685.  
  686.     // we run in English if there is a locale problem
  687.  
  688.     resettime();
  689.  
  690.     if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 39L)))
  691.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open graphics.library V39+!\0", 24);
  692.     cleanexit(EXIT_FAILURE);
  693.     }
  694.     if (!(GadToolsBase = (struct GadToolsBase *) OpenLibrary("gadtools.library", 0L)))
  695.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open gadtools.library!\0", 24);
  696.     cleanexit(EXIT_FAILURE);
  697.     }
  698.     if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 38L)))
  699.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open ASL.library V38+!\0", 24);
  700.     cleanexit(EXIT_FAILURE);
  701.     }
  702.  
  703.     if
  704.     (   (DiskFontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L))
  705.      && (FontPtr = (struct TextFont *) OpenDiskFont(&WormWars8))
  706.     )
  707.     {   fonttag = (ULONG) &WormWars8;
  708.     } else
  709.     {   fonttag = (ULONG) &Topaz8;
  710.     }
  711.  
  712.     hero[BEOWULF  ].control = HUMAN;
  713.     hero[BRUNHILD ].control = NONE;
  714.     hero[EGIL     ].control = NONE;
  715.     hero[RAGNAR   ].control = AMIGA;
  716.     hero[SIEGFRIED].control = NONE;
  717.     hero[STARKAD  ].control = NONE;
  718.  
  719.     ok = FALSE;
  720.     if (FileHandle = Open("PROGDIR:Saga.config", MODE_OLDFILE))
  721.     {   if (Read(FileHandle, IOBuffer, CONFIGLENGTH) == CONFIGLENGTH)
  722.         {   ok = TRUE;
  723.             for (whichhero = 0; whichhero <= HEROES; whichhero++)
  724.             {   hero[whichhero].control = (SLONG) ((SBYTE) IOBuffer[whichhero]);
  725.             }
  726.             DisplayID     = (ULONG) (  (IOBuffer[ 6] * 16777216)
  727.                                      + (IOBuffer[ 7] *    65536)
  728.                                      + (IOBuffer[ 8] *      256)
  729.                                      +  IOBuffer[ 9]            );
  730.             DisplayWidth  = (ULONG) (  (IOBuffer[10] * 16777216)
  731.                                      + (IOBuffer[11] *    65536)
  732.                                      + (IOBuffer[12] *      256)
  733.                                      +  IOBuffer[13]            );
  734.             DisplayHeight = (ULONG) (  (IOBuffer[14] * 16777216)
  735.                                      + (IOBuffer[15] *    65536)
  736.                                      + (IOBuffer[16] *      256)
  737.                                      +  IOBuffer[17]            );
  738.             DisplayDepth  = (UWORD) (  (IOBuffer[18] *      256)
  739.                                      +  IOBuffer[19]            );
  740.             speed         = (WORD)      IOBuffer[20];
  741.             titlebar      = (FLAG)      IOBuffer[21];
  742.             advanced      = (FLAG)      IOBuffer[22];
  743.         }
  744.         Close(FileHandle);
  745.         // FileHandle = NULL;
  746.     }
  747.  
  748.     if (advanced)
  749.     {   monsters = 30;
  750.         treasures = 5;
  751.     } else
  752.     {   monsters = 26;
  753.         treasures = 3;
  754.     }
  755.  
  756.     /* argument parsing */
  757.  
  758.     if (argc) /* started from CLI */
  759.     {   if (!(ArgsPtr = ReadArgs
  760.         (   "BEOWULF/K,BRUNHILD/K,EGIL/K,RAGNAR/K,SIEGFRIED/K,STARKAD/K,NODBUF/S,FILE",
  761.             (LONG *) args,
  762.             NULL
  763.         )))
  764.         {   Printf
  765.             (   "%s: %s "
  766.                 "[BEOWULF=HUMAN|AMIGA|NONE] "
  767.                 "[BRUNHILD=HUMAN|AMIGA|NONE] "
  768.                 "[EGIL=HUMAN|AMIGA|NONE] "
  769.                 "[RAGNAR=HUMAN|AMIGA|NONE] "
  770.                 "[SIEGFRIED=HUMAN|AMIGA|NONE] "
  771.                 "[STARKAD=HUMAN|AMIGA|NONE] "
  772.                 "[[FILE=]<savedgame>]\n",
  773.                 GetCatalogStr(li.li_Catalog, MSG_USAGE, "Usage"),
  774.                 argv[0]
  775.             );
  776.             cleanexit(EXIT_FAILURE);
  777.         }
  778.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  779.         {   if (args[whichhero])
  780.             {   if (!stricmp((STRPTR) args[whichhero], "HUMAN"))
  781.                 {   hero[whichhero].control = HUMAN;
  782.                 } elif (!stricmp((STRPTR) args[whichhero], "AMIGA"))
  783.                 {   hero[whichhero].control = AMIGA;
  784.                 } elif (!stricmp((STRPTR) args[whichhero], "NONE"))
  785.                 {   hero[whichhero].control = NONE;
  786.                 } else
  787.                 {   Printf("%s: Hero control must be HUMAN, AMIGA or NONE\n", argv[0]); // localize?
  788.         }   }   }
  789.         if (args[6])
  790.         {   nodbuf = TRUE;
  791.         }
  792.         if (args[7])
  793.         {   strcpy(pathname, (STRPTR) args[7]);
  794.             cliload = TRUE;
  795.     }   }
  796.  
  797.     strcpy(smrstring, "Saga: ");
  798.     strcat(smrstring, GetCatalogStr(li.li_Catalog, MSG_S_M_R, "Screen Mode Requester"));
  799.  
  800.     if (!ok)
  801.     {   if (!(smr = (struct ScreenModeRequester *) AllocAslRequestTags
  802.         (   ASL_ScreenModeRequest,
  803.             ASLSM_TitleText,            smrstring,
  804.             ASLSM_InitialDisplayID,     HIRES_KEY | PAL_MONITOR_ID | LACE,
  805.             ASLSM_InitialDisplayWidth,  SCREENXPIXEL,
  806.             ASLSM_InitialDisplayHeight, SCREENYPIXEL,
  807.             ASLSM_InitialDisplayDepth,  DEPTH,
  808.             ASLSM_DoWidth,              TRUE,
  809.             ASLSM_DoHeight,             TRUE,
  810.             ASLSM_DoDepth,              TRUE,
  811.             ASLSM_MinWidth,             SCREENXPIXEL,
  812.             ASLSM_MinHeight,            SCREENYPIXEL,
  813.             ASLSM_MinDepth,             MINDEPTH,
  814.             TAG_DONE
  815.         )))
  816.         {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create ASL screen mode request!\0", 24);
  817.             cleanexit(EXIT_FAILURE);
  818.         }
  819.         if (AslRequest(smr, 0L))
  820.         {   DisplayID     = smr->sm_DisplayID;
  821.             DisplayWidth  = smr->sm_DisplayWidth;
  822.             DisplayHeight = smr->sm_DisplayHeight;
  823.             DisplayDepth  = smr->sm_DisplayDepth;
  824.             FreeAslRequest(smr);
  825.         } else
  826.         {   FreeAslRequest(smr);
  827.             cleanexit(EXIT_SUCCESS);
  828.     }   }
  829.  
  830.     if
  831.     (   GetDisplayInfoData(NULL, (UBYTE *) &QueryInfo, sizeof(struct DisplayInfo), DTAG_DISP, DisplayID)
  832.      && (QueryInfo.PropertyFlags & DIPF_IS_PAL)
  833.     )
  834.     {   aga = TRUE;
  835.         if (!nodbuf)
  836.         {   dbuf = TRUE;
  837.             // Printf("Saga: Double buffering activated.\n");
  838.     }   }
  839.  
  840.     if (LockPubScreen("SAGA"))
  841.     {   publictag = TAG_IGNORE;
  842.     } else
  843.     {   publictag = SA_PubName;
  844.     }
  845.  
  846.     ScreenPtr = (struct Screen *) OpenScreenTags
  847.     (   NULL,
  848.         SA_Width,       DisplayWidth,
  849.         SA_Height,      DisplayHeight,
  850.         SA_Depth,       DisplayDepth,
  851.         SA_DisplayID,   DisplayID,
  852.         SA_Behind,      TRUE,
  853.         SA_AutoScroll,  TRUE,
  854.         SA_ShowTitle,   titlebar,
  855.         SA_Title,       TITLEBAR,
  856.         SA_Font,        fonttag,
  857.         publictag,      "SAGA",
  858.         SA_Colors32,    table1,
  859.         SA_Pens,        Pens,
  860.         TAG_DONE
  861.     ); // we can't use interleaving on AGA screens if we want double buffering
  862.     if (!ScreenPtr)
  863.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open screen!\0", 24);
  864.         cleanexit(EXIT_FAILURE);
  865.     }
  866.  
  867.     saveconfig = TRUE;
  868.  
  869.     if (publictag == SA_PubName)
  870.     {   PubScreenStatus(ScreenPtr, NULL); // take the screen public
  871.     }
  872.  
  873.     for (whichcountry = 36; whichcountry <= 65; whichcountry++)
  874.     {   SetRGB32(&ScreenPtr->ViewPort, 8 + whichcountry, 0x00000000, 0x00000000, 0x99999999);
  875.     }
  876.     LoadRGB32(&(ScreenPtr->ViewPort), table2);
  877.  
  878.     // this must be done before the menus are set up
  879.     if (titlebar)
  880.     {   NewMenu[INDEX_SHOW_TITLEBAR].nm_Flags |= CHECKED;
  881.     }
  882.  
  883.     /* GadTools */
  884.     if (!(VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)))
  885.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't get GadTools visual info!\0", 24);
  886.         cleanexit(EXIT_FAILURE);
  887.     }
  888.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  889.     {   CycleGadget[whichhero].ng_VisualInfo = VisualInfoPtr;
  890.     }
  891.     SpeedGadget.ng_VisualInfo    =
  892.     AdvancedGadget.ng_VisualInfo = VisualInfoPtr;
  893.  
  894.     if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
  895.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create menus!\0", 24);
  896.         cleanexit(EXIT_FAILURE);
  897.     }
  898.     if (!(LayoutMenus(MenuPtr, VisualInfoPtr, GTMN_NewLookMenus, TRUE, TAG_DONE)))
  899.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't lay out menus!\0", 24);
  900.     cleanexit(EXIT_FAILURE);
  901.     }
  902.     if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
  903.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create GadTools context!\0", 24);
  904.     cleanexit(EXIT_FAILURE);
  905.     }
  906.  
  907.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  908.     {   CycleGadgetPtr[whichhero] = PrevGadgetPtr = (struct Gadget *) CreateGadget
  909.         (   CYCLE_KIND,
  910.             PrevGadgetPtr,
  911.             &CycleGadget[whichhero],
  912.             GTCY_Labels, CycleOptions,
  913.             GTCY_Active, hero[whichhero].control,
  914.             TAG_DONE
  915.     );
  916.     }
  917.     SpeedGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  918.     (   SLIDER_KIND,
  919.         PrevGadgetPtr,
  920.         &SpeedGadget,
  921.         GA_RelVerify,     TRUE,
  922.         GTSL_Min,         0,
  923.         GTSL_Max,         6,
  924.         GTSL_Level,       speed,
  925.         GT_Underscore,    '_',
  926.         TAG_DONE
  927.     );
  928.     AdvancedGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  929.     (   CHECKBOX_KIND,
  930.         PrevGadgetPtr,
  931.         &AdvancedGadget,
  932.         GA_RelVerify,     TRUE,
  933.         GTCB_Checked,     (BOOL) advanced,
  934.         GT_Underscore,    '_',
  935.         TAG_DONE
  936.     );
  937.  
  938.     if (dbuf)
  939.     {   if (!(ScreenBuf[0] = AllocScreenBuffer(ScreenPtr, NULL, SB_SCREEN_BITMAP)))
  940.         {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't allocate original screen buffer!\0", 24);
  941.             cleanexit(EXIT_FAILURE);
  942.     }   }
  943.  
  944.     /* main window */
  945.     if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
  946.         WA_Left,                0,
  947.         WA_Top,                 0,
  948.         WA_Width,               DisplayWidth,
  949.         WA_Height,              DisplayHeight,
  950.         WA_Backdrop,            TRUE,
  951.         WA_IDCMP,               IDCMP_RAWKEY
  952.                               | IDCMP_VANILLAKEY
  953.                               | IDCMP_MOUSEBUTTONS
  954.                               | IDCMP_INTUITICKS
  955.                               | IDCMP_CLOSEWINDOW
  956.                               | IDCMP_REFRESHWINDOW
  957.                               | IDCMP_MENUPICK
  958.                               | IDCMP_MENUVERIFY
  959.                               | CYCLEIDCMP
  960.                               | BUTTONIDCMP,
  961.         WA_Flags,               WFLG_BORDERLESS,
  962.         WA_Gadgets,             GListPtr,
  963.         WA_CustomScreen,        ScreenPtr,
  964.         WA_Activate,            TRUE,
  965.         WA_NewLookMenus,        TRUE,
  966.     TAG_DONE)))
  967.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open window!\0", 24);
  968.         cleanexit(EXIT_FAILURE);
  969.     }
  970.  
  971.     /* We could use SCREENXPIXEL and SCREENYPIXEL instead, except that titlebar hiding
  972.     would not then work correctly. */
  973.  
  974.     /* redirection of AmigaDOS system requesters */
  975.     OldWindowPtr = ProcessPtr->pr_WindowPtr;
  976.     ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;
  977.  
  978.     if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "#?.saga", ASL_Window, MainWindowPtr, TAG_DONE)))
  979.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't create ASL file request!\0", 24);
  980.         cleanexit(EXIT_FAILURE);
  981.     }
  982.  
  983.     SetMenuStrip(MainWindowPtr, MenuPtr);
  984.  
  985.     // clean to here
  986.  
  987.     createcounters();
  988.  
  989.     // dirty by here
  990.  
  991.     ScreenToFront(ScreenPtr);
  992.  
  993.     while (1)
  994.     {   titlescreen();
  995.         if (!loaded)
  996.         {   newgame();
  997.         }
  998.         gameloop();
  999. }   }
  1000.  
  1001. MODULE void gameloop(void)
  1002. {   SLONG                bestglory = 0,
  1003.                          besthero  = -1, // to avoid spurious compiler warnings
  1004.                          countertype,
  1005.                          fastest,
  1006.                          heroes    = 0,
  1007.                          strongest,
  1008.                          strongestjarl,
  1009.                          result,
  1010.                          whichhero,
  1011.                          whichjarl,
  1012.                          whichcountry,
  1013.                          whichmonster,
  1014.                          whichtreasure,
  1015.                          whichsord,
  1016.                          winners   = 0;
  1017.     FLAG                 done,
  1018.                          transfer;
  1019.     UWORD                code,
  1020.                          qual;
  1021.     WORD                 mousey;
  1022.     ULONG                class;
  1023.     struct IntuiMessage* MsgPtr;
  1024.     struct MenuItem*     ItemPtr;
  1025.  
  1026.     do
  1027.     {   strcpy(titlestring, TITLEBAR);
  1028.         strcat(titlestring, ": ");
  1029.         sprintf
  1030.         (   saystring,
  1031.             "%s %ld %s %ld",
  1032.             GetCatalogStr(li.li_Catalog, MSG_TURN, "Turn"),
  1033.             turn,
  1034.             GetCatalogStr(li.li_Catalog, MSG_OF, "of"),
  1035.             TURNS
  1036.         );
  1037.         strcat(titlestring, saystring);
  1038.         strcat(saystring, "...");
  1039.         SetWindowTitles(MainWindowPtr, (UBYTE *) -1, titlestring); // this is not copied, it is a pointer
  1040.         say(LOWER);
  1041.         hint
  1042.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK, "OK"),
  1043.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK, "OK")
  1044.         );
  1045.  
  1046.          OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,          NOSUB));
  1047.          OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,         NOSUB));
  1048.          OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS,       NOSUB));
  1049.         result = getevent(MULTIKEYBOARD, NULL);
  1050.         if (result == -4)
  1051.         {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1052.             {   hero[whichhero].alive    = FALSE;
  1053.                 hero[whichhero].verydead = TRUE;
  1054.             }
  1055.             gameover = TRUE;
  1056.         }
  1057.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
  1058.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
  1059.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
  1060.  
  1061.         if (!gameover)
  1062.         {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1063.             {   if (!hero[whichhero].alive && !hero[whichhero].verydead)
  1064.                 {   transfer = FALSE;
  1065.                     for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  1066.                     {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
  1067.                         {   transfer = TRUE;
  1068.                             break; // for speed
  1069.                     }   }
  1070.  
  1071.                     if (hero[whichhero].control == AMIGA)
  1072.                     {   if (transfer)
  1073.                         {   strongest = fastest = strongestjarl = 0;
  1074.                             for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  1075.                             {   if
  1076.                                 (   jarl[whichjarl].alive
  1077.                                  && jarl[whichjarl].hero == whichhero
  1078.                                 )
  1079.                                 {   if (jarl[whichjarl].strength > strongest)
  1080.                                     {   strongest     = jarl[whichjarl].strength;
  1081.                                         fastest       = jarl[whichjarl].moves;
  1082.                                         strongestjarl = whichjarl;
  1083.                                     } elif (jarl[whichjarl].strength == strongest)
  1084.                                     {   if (jarl[whichjarl].moves > fastest)
  1085.                                         {   strongest     = jarl[whichjarl].strength;
  1086.                                             fastest       = jarl[whichjarl].moves;
  1087.                                             strongestjarl = whichjarl;
  1088.                             }   }   }   }
  1089.                             sprintf
  1090.                             (   saystring,
  1091.                                 "%s %s %s %s (%ld-%ld).",
  1092.                                 GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"),
  1093.                                 hero[whichhero].name,
  1094.                                 GetCatalogStr(li.li_Catalog, MSG_PROMOTES_JARL, "promotes jarl"),
  1095.                                 jarl[strongestjarl].name,
  1096.                                 jarl[strongestjarl].strength,
  1097.                                 jarl[strongestjarl].moves
  1098.                             );
  1099.                             promote(whichhero, strongestjarl); // order-dependent
  1100.                         } else
  1101.                         {   if (turn > TURNS / 2)
  1102.                             {   withdraw(whichhero);
  1103.                                 sprintf
  1104.                                 (   saystring,
  1105.                                     "%s %s %s.",
  1106.                                     GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"),
  1107.                                     hero[whichhero].name,
  1108.                                     GetCatalogStr(li.li_Catalog, MSG_WITHDRAWS_FROM_PLAY, "withdraws from play")
  1109.                                 );
  1110.                             } else
  1111.                             {   newhero(whichhero, FALSE);
  1112.                                 sprintf
  1113.                                 (   saystring,
  1114.                                     "%s %s %s.",
  1115.                                     GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"),
  1116.                                     hero[whichhero].name,
  1117.                                     GetCatalogStr(li.li_Catalog, MSG_RESTARTS, "restarts")
  1118.                                 );
  1119.                         }   }
  1120.                         say(LOWER);
  1121.                         anykey();
  1122.                     } elif (hero[whichhero].control == HUMAN)
  1123.                     {   sprintf
  1124.                         (   saystring,
  1125.                             "%s %s, (%s)%s/(%s)%s",
  1126.                             GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO,       "Dead hero"),
  1127.                             hero[whichhero].name,
  1128.                             GetCatalogStr(li.li_Catalog, MSG_CHAR_WITHDRAW,   "W"),
  1129.                             GetCatalogStr(li.li_Catalog, MSG_UNCHAR_WITHDRAW, "ithdraw"),
  1130.                             GetCatalogStr(li.li_Catalog, MSG_CHAR_RESTART,    "R"),
  1131.                             GetCatalogStr(li.li_Catalog, MSG_UNCHAR_RESTART,  "estart")
  1132.                         );
  1133.                         if (transfer)
  1134.                         {   sprintf
  1135.                             (   saystring2,
  1136.                                 "/(%s)%s?",
  1137.                                 GetCatalogStr(li.li_Catalog, MSG_CHAR_TRANSFER,   "T"),
  1138.                                 GetCatalogStr(li.li_Catalog, MSG_UNCHAR_TRANSFER, "ransfer")
  1139.                             );
  1140.                             strcat(saystring, saystring2);
  1141.                         } else
  1142.                         {   strcat(saystring, "?");
  1143.                         }
  1144.                         say(LOWER);
  1145.  
  1146.                         do
  1147.                         {   result = getevent(WRKEYBOARD, NULL);
  1148.                         } while
  1149.                         (   result != onekey[ONEKEY_WITHDRAW]
  1150.                          && result != onekey[ONEKEY_RESTART]
  1151.                          && (!transfer || result != onekey[ONEKEY_TRANSFER])
  1152.                         );
  1153.                         if (result == onekey[ONEKEY_TRANSFER])
  1154.                         {   sprintf
  1155.                             (   saystring,
  1156.                                 "%s %s, %s?",
  1157.                                 GetCatalogStr(li.li_Catalog, MSG_DEAD_HERO, "Dead hero"),
  1158.                                 hero[whichhero].name,
  1159.                                 GetCatalogStr(li.li_Catalog, MSG_S_W_J_T_P, "select which jarl to promote")
  1160.                             );
  1161.                             say(LOWER);
  1162.                             do
  1163.                             {   whichjarl = getevent(COUNTER, &countertype);
  1164.                             } while
  1165.                             (   whichjarl < 0
  1166.                              || countertype != JARL
  1167.                              || jarl[whichjarl].hero != whichhero
  1168.                             );
  1169.                             promote(whichhero, whichjarl);
  1170.                         } elif (result == onekey[ONEKEY_WITHDRAW])
  1171.                         {   withdraw(whichhero);
  1172.                         } elif (result == onekey[ONEKEY_RESTART])
  1173.                         {   newhero(whichhero, FALSE);
  1174.             }   }   }   }
  1175.  
  1176.             phase1(); // movement
  1177.             phase2(); // combat
  1178.             phase3(); // kingdoms
  1179.  
  1180.             /* "4. PLACE MONSTERS. A number of monsters equal to the number
  1181.             of heroes in play are randomly placed face up by rolling two dice
  1182.             and placing the monster in the area indicated. (This is done every
  1183.             turn until all counters are used. "Dead" monsters may not be
  1184.             reused."
  1185.  
  1186.             It's arguable whether monsters and jarls should be added
  1187.             at the end of the last turn. A strict reading of the rules
  1188.             would indicate that they should, but in practical terms it
  1189.             is better not to - adding them causes the new counters to
  1190.             appear on screen just before the screen is blanked, which
  1191.             is an annoying effect. */
  1192.  
  1193.             if (turn < TURNS)
  1194.             {   place_monsters(); // phase 4
  1195.  
  1196.             /* "5. PLACE jarls. A number of jarls equal to the number of
  1197.             heroes in play are randomly placed face up by rolling two dice
  1198.             and placing the jarl in the area indicated. (This is done every
  1199.             turn until all counters are used. "Dead" jarls may not be
  1200.             reused." */
  1201.  
  1202.                 place_jarls();    // phase 5
  1203.  
  1204.                 refreshcounters();
  1205.             }
  1206.  
  1207.             /* 6. MARK TURN. One turn is marked off. */
  1208.  
  1209.             turn++;
  1210.         }
  1211.     } while (turn <= TURNS && !gameover);
  1212.  
  1213.     /* "At the end of the 20th turn the game is over and players total
  1214.     their glory to determine who has won. The turn should be marked off on
  1215.     each player's record sheet." */
  1216.  
  1217.     screenoff();
  1218.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1219.     {   remove_hero(whichhero, FALSE);
  1220.     }
  1221.     for (whichjarl = 0; whichjarl <= JARL; whichjarl++)
  1222.     {   remove_jarl(whichjarl, FALSE);
  1223.     }
  1224.     for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  1225.     {   remove_monster(whichmonster, FALSE);
  1226.     }
  1227.     for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  1228.     {   remove_treasure(whichtreasure, FALSE);
  1229.     }
  1230.     for (whichsord = 0; whichsord <= SORDS; whichsord++)
  1231.     {   remove_sord(whichsord, FALSE);
  1232.     }
  1233.     // no reason to call refreshcounters() as we are about to blank the screen
  1234.     for (whichcountry = 0; whichcountry <= 65; whichcountry++)
  1235.     {   world[whichcountry].hero = -1;
  1236.     }
  1237.     clearscreen();
  1238.     screenon();
  1239.  
  1240.     if (!gameover)
  1241.     {   SetDrMd(MainWindowPtr->RPort, JAM1);
  1242.         SetAPen(MainWindowPtr->RPort, LIGHTGREY);
  1243.         RectFill(MainWindowPtr->RPort, 320 - 70, 187 + TBSIZE, 320 + 70, 187 + TBSIZE + 11);
  1244.  
  1245.         if (DisplayDepth >= DEPTH)
  1246.         {   SetAPen(MainWindowPtr->RPort, WHITE);
  1247.             Move(MainWindowPtr->RPort, 320 - 70, 187 + TBSIZE - 2);
  1248.             Draw(MainWindowPtr->RPort, 320 + 70, 187 + TBSIZE - 2);
  1249.         }
  1250.  
  1251.         SetAPen(MainWindowPtr->RPort, BLACK);
  1252.         Move(MainWindowPtr->RPort, 320 - 70, 187 + TBSIZE - 1);
  1253.         Draw(MainWindowPtr->RPort, 320 + 70, 187 + TBSIZE - 1);
  1254.         Move(MainWindowPtr->RPort, 320 - 70, 187 + TBSIZE + 12);
  1255.         Draw(MainWindowPtr->RPort, 320 + 70, 187 + TBSIZE + 12);
  1256.  
  1257.         strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_HERO_NAME, "Hero Name"));
  1258.         Move(MainWindowPtr->RPort, 320 - 70 + 4, 187 + TBSIZE + 8);
  1259.         Text(MainWindowPtr->RPort, saystring, strlen(saystring));
  1260.  
  1261.         strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_GLORY, "Glory"));
  1262.         Move(MainWindowPtr->RPort, 320 + 70 - (8 * 4) - 4 + (8 * (4 - strlen(saystring))), 187 + TBSIZE + 8);
  1263.         Text(MainWindowPtr->RPort, saystring, strlen(saystring));
  1264.  
  1265.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1266.         {   if (hero[whichhero].control != NONE)
  1267.             {   heroes++;
  1268.                 hero[whichhero].glory += hero[whichhero].wealth / 10;
  1269.                 hero[whichhero].glory += hero[whichhero].luck   /  3;
  1270.                 if
  1271.                 (   treasure[BROSUNGNECKLACE].possessortype == HERO
  1272.                  && treasure[BROSUNGNECKLACE].possessor == whichhero
  1273.                 )
  1274.                 {   hero[whichhero].wealth += 20;
  1275.                 }
  1276.                 for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  1277.                 {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichhero)
  1278.                     {   hero[whichhero].glory += jarl[whichjarl].strength / 2;
  1279.                         if
  1280.                         (   treasure[BROSUNGNECKLACE].possessortype == JARL
  1281.                          && treasure[BROSUNGNECKLACE].possessor == whichjarl
  1282.                         )
  1283.                         {   hero[whichhero].wealth += 20;
  1284.                 }   }   }
  1285.                 if (hero[whichhero].glory >= 15)
  1286.                 {   SetAPen(MainWindowPtr->RPort, GREEN);
  1287.                 } else
  1288.                 {   SetAPen(MainWindowPtr->RPort, RED);
  1289.                 }
  1290.                 RectFill(MainWindowPtr->RPort, 320 - 70, 187 + TBSIZE + (heroes * SCOREDISTANCE), 320 + 70, 187 + TBSIZE + 11 + (heroes * SCOREDISTANCE));
  1291.  
  1292.                 SetAPen(MainWindowPtr->RPort, BLACK);
  1293.                 Move(MainWindowPtr->RPort, 320 - 70 + 4, 187 + TBSIZE + 8 + (heroes * SCOREDISTANCE));
  1294.                 Text(MainWindowPtr->RPort, hero[whichhero].name, strlen(hero[whichhero].name));
  1295.  
  1296.                 stcl_d(numberstring, hero[whichhero].glory);
  1297.                 Move(MainWindowPtr->RPort, 320 + 70 - (8 * 4) - 4 + (8 * (4 - strlen(numberstring))), 187 + TBSIZE + 8 + (heroes * SCOREDISTANCE));
  1298.                 Text(MainWindowPtr->RPort, numberstring, strlen(numberstring));
  1299.  
  1300.                 Move(MainWindowPtr->RPort, 320 - 70, 199 + TBSIZE + (heroes * SCOREDISTANCE));
  1301.                 Draw(MainWindowPtr->RPort, 320 + 70, 199 + TBSIZE + (heroes * SCOREDISTANCE));
  1302.         }   }
  1303.  
  1304.         if (DisplayDepth >= DEPTH)
  1305.         {   SetAPen(MainWindowPtr->RPort, WHITE);
  1306.             Move(MainWindowPtr->RPort, 249, 185 + TBSIZE);
  1307.             Draw(MainWindowPtr->RPort, 249, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1308.         }
  1309.  
  1310.         SetAPen(MainWindowPtr->RPort, BLACK);
  1311.         Move(MainWindowPtr->RPort, 250, 187 + TBSIZE);
  1312.         Draw(MainWindowPtr->RPort, 250, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1313.         Move(MainWindowPtr->RPort, 340, 187 + TBSIZE);
  1314.         Draw(MainWindowPtr->RPort, 340, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1315.         Move(MainWindowPtr->RPort, 390, 187 + TBSIZE);
  1316.         Draw(MainWindowPtr->RPort, 390, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1317.         Move(MainWindowPtr->RPort, 391, 187 + TBSIZE);
  1318.         Draw(MainWindowPtr->RPort, 391, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1319.         Draw(MainWindowPtr->RPort, 250, 187 + TBSIZE + ((heroes + 1) * SCOREDISTANCE));
  1320.  
  1321.         strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_GAME_OVER, "Game over"));
  1322.         strcat(saystring, "!");
  1323.  
  1324.         if (heroes > 1)
  1325.         {   // determine winner
  1326.             for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1327.             {   if (hero[whichhero].control != NONE && hero[whichhero].glory >= bestglory)
  1328.                 {   bestglory = hero[whichhero].glory;
  1329.             }   }
  1330.             for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1331.             {   if (hero[whichhero].control != NONE && hero[whichhero].glory == bestglory)
  1332.                 {   winners++;
  1333.                     besthero = whichhero;
  1334.             }   }
  1335.  
  1336.             if (winners == 1)
  1337.             {   strcat(saystring, " ");
  1338.                 strcat(saystring, hero[besthero].name);
  1339.                 strcat(saystring, " ");
  1340.                 strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_WINS, "wins"));
  1341.                 strcat(saystring, "!");
  1342.         }   }
  1343.  
  1344.         SetAPen(MainWindowPtr->RPort, BLACK);
  1345.         Move(MainWindowPtr->RPort, 4 + 1, MESSAGEY + 16 + 1);
  1346.         Text(MainWindowPtr->RPort, saystring, strlen(saystring));
  1347.         SetAPen(MainWindowPtr->RPort, WHITE);
  1348.         Move(MainWindowPtr->RPort, 4    , MESSAGEY + 16    );
  1349.         Text(MainWindowPtr->RPort, saystring, strlen(saystring));
  1350.  
  1351. /*      say(LOWER);
  1352.         hint
  1353.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK, "OK"),
  1354.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK, "OK")
  1355.         ); */
  1356.  
  1357.         Delay(50);
  1358.         clearkybd();
  1359.         done = FALSE;
  1360.         do
  1361.         {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  1362.             MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort);
  1363.             class  = MsgPtr->Class;
  1364.             code   = MsgPtr->Code;
  1365.             qual   = MsgPtr->Qualifier;
  1366.             mousey = MsgPtr->MouseY;
  1367.             if (class == IDCMP_MENUVERIFY && code == MENUHOT && mousey > TBSIZE)
  1368.             {   if (!(qual & IEQUALIFIER_RCOMMAND))
  1369.                 {   MsgPtr->Code = MENUCANCEL;
  1370.             }   }
  1371.             GT_ReplyIMsg(MsgPtr);
  1372.  
  1373.             switch(class)
  1374.             {
  1375.             case IDCMP_CLOSEWINDOW:
  1376.                 cleanexit(EXIT_SUCCESS);
  1377.             acase IDCMP_REFRESHWINDOW:
  1378.                 GT_BeginRefresh(MainWindowPtr);
  1379.                 GT_EndRefresh(MainWindowPtr, TRUE);
  1380.             acase IDCMP_MOUSEBUTTONS:
  1381.             case IDCMP_VANILLAKEY:
  1382.             case IDCMP_RAWKEY:
  1383.                 done = TRUE;
  1384.             acase IDCMP_MENUPICK:
  1385.                 while (code != MENUNULL)
  1386.                 {   ItemPtr = ItemAddress(MenuPtr, code);
  1387.  
  1388.                     switch (MENUNUM(code))
  1389.                     {
  1390.                     case MN_PROJECT:
  1391.                         switch (ITEMNUM(code))
  1392.                         {
  1393.                         case IN_QUIT:
  1394.                             cleanexit(EXIT_SUCCESS);
  1395.                         adefault:
  1396.                             // IN_OPEN
  1397.                         break;
  1398.                         }
  1399.                     acase MN_SETTINGS:
  1400.                         switch(ITEMNUM(code))
  1401.                         {
  1402.                         case IN_SHOW_TITLEBAR:
  1403.                             if (ItemPtr->Flags & CHECKED)
  1404.                             {   titlebar = TRUE;
  1405.                             } else
  1406.                             {   titlebar = FALSE;
  1407.                             }
  1408.                             ShowTitle(ScreenPtr, titlebar);
  1409.                         adefault:
  1410.                         break;
  1411.                         }
  1412.                     acase MN_HELP:
  1413.                         switch(ITEMNUM(code))
  1414.                         {
  1415.                         case IN_GAME_SUMMARY:
  1416.                             summarywindow();
  1417.                         acase IN_HELP_1:
  1418.                             docwindow(1);
  1419.                         acase IN_HELP_2:
  1420.                             docwindow(2);
  1421.                         acase IN_HELP_3:
  1422.                             docwindow(3);
  1423.                         acase IN_HELP_4:
  1424.                             docwindow(4);
  1425.                         acase IN_ABOUT:
  1426.                             helpabout();
  1427.                         adefault:
  1428.                         break;
  1429.                         }
  1430.                     adefault:
  1431.                     break;
  1432.                     }
  1433.                     code = ItemPtr->NextSelect;
  1434.                 }
  1435.             adefault: // IDCMP_MENUVERIFY, etc.
  1436.             break;
  1437.             }
  1438.         } while (!done);
  1439. }   }
  1440.  
  1441. EXPORT void cleanexit(SLONG rc)
  1442. {   BPTR  FileHandle /* = NULL */ ;
  1443.     SLONG whichhero;
  1444.  
  1445.     destroycounters();
  1446.  
  1447.     if (ASLRqPtr)
  1448.     {   FreeAslRequest(ASLRqPtr);
  1449.         ASLRqPtr = NULL;
  1450.     }
  1451.     if (OldWindowPtr)
  1452.     {   ProcessPtr->pr_WindowPtr = OldWindowPtr;
  1453.     }
  1454.  
  1455.     /* It does not matter whether there are outstanding messages for a
  1456.     window when it is closed, provided that the window does not use a
  1457.     shared IDCMP message port. */
  1458.  
  1459.     if (InfoWindowPtr)
  1460.     {   CloseWindow(InfoWindowPtr);
  1461.         InfoWindowPtr = NULL;
  1462.     }
  1463.     if (HelpWindowPtr)
  1464.     {   CloseWindow(HelpWindowPtr);
  1465.         HelpWindowPtr = NULL;
  1466.     }
  1467.     if (MainWindowPtr)
  1468.     {   ClearMenuStrip(MainWindowPtr);
  1469.         CloseWindow(MainWindowPtr);
  1470.         MainWindowPtr = NULL;
  1471.     }
  1472.     if (GListPtr)
  1473.     {   FreeGadgets(GListPtr);
  1474.         GListPtr = NULL;
  1475.     }
  1476.     if (MenuPtr)
  1477.     {   FreeMenus(MenuPtr);
  1478.         MenuPtr = NULL;
  1479.     }
  1480.     if (VisualInfoPtr)
  1481.     {   FreeVisualInfo(VisualInfoPtr);
  1482.         VisualInfoPtr = NULL;
  1483.     }
  1484.     if (ScreenPtr)
  1485.     {   if (ScreenBuf[1])
  1486.         {   FreeScreenBuffer(ScreenPtr, ScreenBuf[1]);
  1487.             ScreenBuf[1] = NULL;
  1488.         }
  1489.         if (ScreenBuf[0])
  1490.         {   FreeScreenBuffer(ScreenPtr, ScreenBuf[0]);
  1491.             ScreenBuf[0] = NULL;
  1492.         }
  1493.         CloseScreen(ScreenPtr);
  1494.         ScreenPtr = NULL;
  1495.     }
  1496.     if (FontPtr)
  1497.     {   CloseFont(FontPtr);
  1498.         FontPtr = NULL;
  1499.     }
  1500.     if (DiskFontBase)
  1501.     {   CloseLibrary((struct Library *) DiskFontBase);
  1502.         DiskFontBase = NULL;
  1503.     }
  1504.     if (ASLBase)
  1505.     {   CloseLibrary((struct Library *) ASLBase);
  1506.         ASLBase = NULL;
  1507.     }
  1508.     if (GadToolsBase)
  1509.     {   CloseLibrary((struct Library *) GadToolsBase);
  1510.         GadToolsBase = NULL;
  1511.     }
  1512.     if (GfxBase)
  1513.     {   CloseLibrary((struct Library *) GfxBase);
  1514.         GfxBase = NULL;
  1515.     }
  1516.     if (LocaleBase)
  1517.     {   CloseCatalog(li.li_Catalog);
  1518.         CloseLibrary((struct Library *) LocaleBase);
  1519.         LocaleBase = NULL;
  1520.     }
  1521.     if (IntuitionBase)
  1522.     {   OpenWorkBench();
  1523.         CloseLibrary((struct Library *) IntuitionBase);
  1524.         IntuitionBase = NULL;
  1525.     }
  1526.     if (ArgsPtr)
  1527.     {   FreeArgs(ArgsPtr);
  1528.         ArgsPtr = NULL;
  1529.     }
  1530.  
  1531.     if (saveconfig)
  1532.     {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1533.         {   IOBuffer[whichhero] = (SBYTE) hero[whichhero].control;
  1534.         }
  1535.         IOBuffer[ 6] = (UBYTE)   (DisplayID     / 16777216);
  1536.         IOBuffer[ 7] = (UBYTE)  ((DisplayID     % 16777216) / 65536);
  1537.         IOBuffer[ 8] = (UBYTE) (((DisplayID     % 16777216) % 65536) / 256);
  1538.         IOBuffer[ 9] = (UBYTE) (((DisplayID     % 16777216) % 65536) % 256);
  1539.         IOBuffer[10] = (UBYTE)   (DisplayWidth  / 16777216);
  1540.         IOBuffer[11] = (UBYTE)  ((DisplayWidth  % 16777216) / 65536);
  1541.         IOBuffer[12] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) / 256);
  1542.         IOBuffer[13] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) % 256);
  1543.         IOBuffer[14] = (UBYTE)   (DisplayHeight / 16777216);
  1544.         IOBuffer[15] = (UBYTE)  ((DisplayHeight % 16777216) / 65536);
  1545.         IOBuffer[16] = (UBYTE) (((DisplayHeight % 16777216) % 65536) / 256);
  1546.         IOBuffer[17] = (UBYTE) (((DisplayHeight % 16777216) % 65536) % 256);
  1547.         IOBuffer[18] = (UBYTE)   (DisplayDepth  / 65536);
  1548.         IOBuffer[19] = (UBYTE)   (DisplayDepth  % 65536);
  1549.         IOBuffer[20] = (UBYTE)    speed;
  1550.         IOBuffer[21] = (UBYTE)    titlebar;
  1551.         IOBuffer[22] = (UBYTE)    advanced;
  1552.         if (FileHandle = Open("PROGDIR:Saga.config", MODE_NEWFILE))
  1553.         {   Write(FileHandle, IOBuffer, CONFIGLENGTH);
  1554.             Close(FileHandle);
  1555.             // FileHandle = NULL;
  1556.     }   }
  1557.  
  1558.     exit(rc); // End of program.
  1559. }
  1560.  
  1561. EXPORT void say(SLONG position)
  1562. {   AUTO    SLONG length;
  1563.     PERSIST TEXT  oldupper[80 + 1] = "";
  1564.  
  1565.     length = strlen(saystring);
  1566.  
  1567.     SetAPen(MainWindowPtr->RPort, BLACK);
  1568.     if (position == UPPER)
  1569.     {   if (strcmp(saystring, oldupper))
  1570.         {   RectFill
  1571.             (   MainWindowPtr->RPort,
  1572.                 0,   MESSAGEY,
  1573.                 639, MESSAGEY + 7
  1574.             );
  1575.             SetAPen(MainWindowPtr->RPort, WHITE);
  1576.             Move(MainWindowPtr->RPort, 4, MESSAGEY + 6);
  1577.             Text(MainWindowPtr->RPort, saystring, length);
  1578.             strcpy(oldupper, saystring);
  1579.     }   }
  1580.     else
  1581.     {   assert(position == LOWER);
  1582.         RectFill
  1583.         (   MainWindowPtr->RPort,
  1584.             0,   MESSAGEY + 10,
  1585.             639, MESSAGEY + 27
  1586.         );
  1587.         SetAPen(MainWindowPtr->RPort, WHITE);
  1588.         Move(MainWindowPtr->RPort, 4, MESSAGEY + 16);
  1589.         if (length > 79)
  1590.         {   Text(MainWindowPtr->RPort, saystring, 79);
  1591.             Move(MainWindowPtr->RPort, 4, MESSAGEY + 26);
  1592.             Text(MainWindowPtr->RPort, &saystring[79], length - 79);
  1593.         } else
  1594.         {   Text(MainWindowPtr->RPort, saystring, length);
  1595. }   }   }
  1596.  
  1597. EXPORT SLONG getevent(SLONG mode, SLONG* countertype)
  1598. {   AUTO    UWORD                code,
  1599.                                  qual;
  1600.     AUTO    ULONG                class;
  1601.     AUTO    struct IntuiMessage* MsgPtr;
  1602.     AUTO    LONG                 country;
  1603.     AUTO    SLONG                counter,
  1604.                                  ticks = 0;
  1605.     AUTO    WORD                 mousex, mousey;
  1606.     AUTO    struct MenuItem*     ItemPtr;
  1607.     PERSIST SLONG                cheat = 0;
  1608.  
  1609.     /* return codes:
  1610.     -4: Escape
  1611.     -3: spacebar
  1612.     -2: backspace
  1613.     -1: invalid country */
  1614.  
  1615.     switch (mode)
  1616.     {
  1617.     case ANYKEY:
  1618.         hint
  1619.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK,    "OK"),
  1620.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_OK,    "OK")
  1621.         );
  1622.     break;
  1623.     case YNKEYBOARD:
  1624.         hint
  1625.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_YES,   "Yes"),
  1626.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_NO,    "No")
  1627.         );
  1628.     break;
  1629.     case GLKEYBOARD:
  1630.         hint
  1631.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_GLORY, "Glory"),
  1632.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_LUCK,  "Luck")
  1633.         );
  1634.     break;
  1635.     case WRKEYBOARD:
  1636.         hint
  1637.         (   (STRPTR) GetCatalogStr(li.li_Catalog, MSG_WITHDRAW, "Withdraw"),
  1638.             (STRPTR) GetCatalogStr(li.li_Catalog, MSG_RESTART,  "Restart")
  1639.         );
  1640.     break;
  1641.     default:
  1642.         // Routines which use MULTIKEYBOARD or COUNTER or COUNTRY must call hint() themselves
  1643.     break;
  1644.     }
  1645.  
  1646.     clearkybd();
  1647.     while(1)
  1648.     {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  1649.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  1650.         {   class  = MsgPtr->Class;
  1651.             code   = MsgPtr->Code;
  1652.             mousex = MsgPtr->MouseX;
  1653.             mousey = MsgPtr->MouseY;
  1654.             qual   = MsgPtr->Qualifier;
  1655.             if (class == IDCMP_MENUVERIFY && code == MENUHOT && mousey > TBSIZE)
  1656.             {   if (!(qual & IEQUALIFIER_RCOMMAND))
  1657.                 {   MsgPtr->Code = MENUCANCEL;
  1658.             }   }
  1659.             GT_ReplyIMsg(MsgPtr);
  1660.  
  1661.             switch(class)
  1662.             {
  1663.             case IDCMP_CLOSEWINDOW:
  1664.                 cleanexit(EXIT_SUCCESS);
  1665.             break;
  1666.             case IDCMP_REFRESHWINDOW:
  1667.                 GT_BeginRefresh(MainWindowPtr);
  1668.                 GT_EndRefresh(MainWindowPtr, TRUE);
  1669.             break;
  1670.             case IDCMP_MOUSEBUTTONS:
  1671.                 if
  1672.                 (   code == SELECTDOWN
  1673.                  && !(qual & IEQUALIFIER_REPEAT)
  1674.                 )
  1675.                 {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1676.                     {   counter = checkcounters(mousex, mousey, countertype);
  1677.                         if (counter == -1)
  1678.                         {   country = checkcountry(mousex, mousey);
  1679.                             if (country >= 0)
  1680.                             {   infowindow(KINGDOM, country);
  1681.                             } else
  1682.                             {   summarywindow();
  1683.                         }   }
  1684.                         else
  1685.                         {   infowindow(*(countertype), counter);
  1686.                     }   }
  1687.                     else
  1688.                     {   switch(mode)
  1689.                         {
  1690.                         case MULTIKEYBOARD:
  1691.                         case ANYKEY:
  1692.                             return('0');
  1693.                         break;
  1694.                         case YNKEYBOARD:
  1695.                             return(onekey[ONEKEY_YES]);
  1696.                         break;
  1697.                         case GLKEYBOARD:
  1698.                             return(onekey[ONEKEY_GLORY]);
  1699.                         break;
  1700.                         case WRKEYBOARD:
  1701.                             return(onekey[ONEKEY_WITHDRAW]);
  1702.                         break;
  1703.                         case COUNTER:
  1704.                         case COUNTRY:
  1705.                             if (mousey >= MESSAGEY)
  1706.                             {   return(-3);
  1707.                             }
  1708.                             counter = checkcounters(mousex, mousey, countertype);
  1709.                             if (counter == -1)
  1710.                             {   country = checkcountry(mousex, mousey);
  1711.                                 *(countertype) = KINGDOM;
  1712.                                 flash(country);
  1713.                                 return(country);
  1714.                             } else
  1715.                             {   if (mode == COUNTER)
  1716.                                 {   return(counter);
  1717.                                 }
  1718.                                 assert(mode == COUNTRY);
  1719.                                 if (*(countertype) == HERO)
  1720.                                 {   flash(hero[counter].where);
  1721.                                     return(hero[counter].where);
  1722.                                 } elif (*(countertype) == JARL)
  1723.                                 {   flash(jarl[counter].where);
  1724.                                     return(jarl[counter].where);
  1725.                                 } elif (*(countertype) == MONSTER)
  1726.                                 {   flash(monster[counter].where);
  1727.                                     return(monster[counter].where);
  1728.                                 } elif (*(countertype) == SORD)
  1729.                                 {   flash(sord[counter].where);
  1730.                                     return(sord[counter].where);
  1731.                                 } elif (*(countertype) == TREASURE)
  1732.                                 {   flash(treasure[counter].where);
  1733.                                     return(treasure[counter].where);
  1734.                             }   }
  1735.                         break;
  1736.                         default:
  1737.                             assert(0);
  1738.                         break;
  1739.                 }   }   }
  1740.                 elif
  1741.                 (    (code == MIDDLEDOWN || code == MENUUP)
  1742.                  && !(qual & IEQUALIFIER_REPEAT)
  1743.                 )
  1744.                 {   if (mode == MULTIKEYBOARD)
  1745.                     {   return('0');
  1746.                     } elif (mode == YNKEYBOARD)
  1747.                     {   return(onekey[ONEKEY_NO]);
  1748.                     } elif (mode == GLKEYBOARD)
  1749.                     {   return(onekey[ONEKEY_LUCK]);
  1750.                     } elif (mode == WRKEYBOARD)
  1751.                     {   return(onekey[ONEKEY_RESTART]);
  1752.                     } elif (mode != ANYKEY || tickspeed[speed] == -1)
  1753.                     {   return(-3);
  1754.                 }   }
  1755.             break;
  1756.             case IDCMP_INTUITICKS:
  1757.                 if (mode == ANYKEY && tickspeed[speed] != -1)
  1758.                 {   ticks++;
  1759.                     if (ticks >= tickspeed[speed])
  1760.                     {   return(-3);
  1761.                 }   }
  1762.                 counter = checkcounters(mousex, mousey, countertype);
  1763.                 if (counter == -1)
  1764.                 {   country = checkcountry(mousex, mousey);
  1765.                     *(countertype) = KINGDOM;
  1766.                     showcountry(country);
  1767.                 } else
  1768.                 {   if (*(countertype) == HERO)
  1769.                     {   saywho(HERO, counter, FALSE, FALSE);
  1770.                         strcat(saystring, "(");
  1771.                         stcl_d(numberstring, hero[counter].strength);
  1772.                         strcat(saystring, numberstring);
  1773.                         strcat(saystring, "-");
  1774.                         stcl_d(numberstring, hero[counter].moves);
  1775.                         strcat(saystring, numberstring);
  1776.                         strcat(saystring, ")");
  1777.                         say(UPPER);
  1778.                     } elif (*(countertype) == JARL)
  1779.                     {   if (jarl[counter].face == FACEDOWN)
  1780.                         {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_UNKNOWN_JARL, "Unknown jarl"));
  1781.                             strcat(saystring, " (?-?)");
  1782.                         } else
  1783.                         {   saywho(JARL, counter, FALSE, FALSE);
  1784.                             strcat(saystring, "(");
  1785.                             stcl_d(numberstring, jarl[counter].strength);
  1786.                             strcat(saystring, numberstring);
  1787.                             strcat(saystring, "-");
  1788.                             stcl_d(numberstring, jarl[counter].moves);
  1789.                             strcat(saystring, numberstring);
  1790.                             strcat(saystring, ")");
  1791.                         }
  1792.                         say(UPPER);
  1793.                     } elif (*(countertype) == MONSTER)
  1794.                     {   strcpy(saystring, monstertypes[monster[counter].species]);
  1795.                         strcat(saystring, " ");
  1796.                         strcat(saystring, monster[counter].name);
  1797.                         strcat(saystring, " (");
  1798.                         stcl_d(numberstring, monster[counter].strength);
  1799.                         strcat(saystring, numberstring);
  1800.                         strcat(saystring, "-");
  1801.                         stcl_d(numberstring, monster[counter].moves);
  1802.                         strcat(saystring, numberstring);
  1803.                         strcat(saystring, ")");
  1804.                         say(UPPER);
  1805.                     } elif (*(countertype) == TREASURE)
  1806.                     {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_THE, "The"));
  1807.                         strcat(saystring, " ");
  1808.                         strcat(saystring, treasure[counter].name);
  1809.                         strcat(saystring, " ");
  1810.                         strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_TREASURE2, "treasure"));
  1811.                         say(UPPER);
  1812.                     } elif (*(countertype) == SORD)
  1813.                     {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
  1814.                         strcat(saystring, " ");
  1815.                         strcat(saystring, sord[counter].name);
  1816.                         say(UPPER);
  1817.                 }   }
  1818.             break;
  1819.             case IDCMP_VANILLAKEY:
  1820.                 if (code == ' ' && (mode != ANYKEY || tickspeed[speed] == -1))
  1821.                 {   return(-3);
  1822.                 } elif (code == 27) // Escape
  1823.                 {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1824.                     {   cleanexit(EXIT_SUCCESS);
  1825.                     } elif (mode != ANYKEY || tickspeed[speed] == -1)
  1826.                     {   return(-4);
  1827.                 }   }
  1828.                 elif
  1829.                 (    mode == MULTIKEYBOARD
  1830.                  ||  mode == GLKEYBOARD
  1831.                  ||  mode == YNKEYBOARD
  1832.                  ||  mode == WRKEYBOARD
  1833.                  || (mode == ANYKEY && tickspeed[speed] == -1)
  1834.                 )
  1835.                 {   code = toupper(code);
  1836.                     return((SLONG) code);
  1837.                 } elif (code == 8) // backspace
  1838.                 {   if (mode != ANYKEY || tickspeed[speed] == -1)
  1839.                     {   return(-2);
  1840.                 }   }
  1841.             break;
  1842.             case IDCMP_RAWKEY:
  1843.                 switch(code)
  1844.                 {
  1845.                 case HELP:
  1846.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1847.                     {   summarywindow();
  1848.                     } else
  1849.                     {   counter = checkcounters(mousex, mousey, countertype);
  1850.                         if (counter == -1)
  1851.                         {   country = checkcountry(mousex, mousey);
  1852.                             if (country >= 0)
  1853.                             {   infowindow(KINGDOM, country);
  1854.                             } else
  1855.                             {   summarywindow();
  1856.                         }   }
  1857.                         else
  1858.                         {   infowindow(*(countertype), counter);
  1859.                     }   }
  1860.                 break;
  1861.                 default:
  1862.                     if
  1863.                     (   (    mode == MULTIKEYBOARD
  1864.                          || (mode == ANYKEY && tickspeed[speed] == -1)
  1865.                         )
  1866.                      &&  code < KEYUP
  1867.                      && (code < FIRSTQUALIFIER || code > LASTQUALIFIER)
  1868.                     )
  1869.                     {   if (code == SCAN_F1 + cheat)
  1870.                         {   cheat++;
  1871.                             if (cheat == 5)
  1872.                             {   cheat = 0;
  1873.                                 hero[BEOWULF].luck = 5000;
  1874.                                 DisplayBeep(ScreenPtr);
  1875.                         }   }
  1876.                         else cheat = 0;
  1877.                     }
  1878.                 break;
  1879.                 }
  1880.             break;
  1881.             case IDCMP_MENUPICK:
  1882.                 while (code != MENUNULL)
  1883.                 {   ItemPtr = ItemAddress(MenuPtr, code);
  1884.  
  1885.                     switch (MENUNUM(code))
  1886.                     {
  1887.                     case MN_PROJECT:
  1888.                         switch (ITEMNUM(code))
  1889.                         {
  1890.                         case IN_NEW:
  1891.                             return(-4);
  1892.                         case IN_SAVE:
  1893.                             savegame(FALSE);
  1894.                         break;
  1895.                         case IN_SAVEAS:
  1896.                             savegame(TRUE);
  1897.                         break;
  1898.                         case IN_QUIT:
  1899.                             cleanexit(EXIT_SUCCESS);
  1900.                         break;
  1901.                         default:
  1902.                             // IN_OPEN
  1903.                         break;
  1904.                         }
  1905.                     break;
  1906.                     case MN_SETTINGS:
  1907.                         switch(ITEMNUM(code))
  1908.                         {
  1909.                         case IN_SHOW_TITLEBAR:
  1910.                             if (ItemPtr->Flags & CHECKED)
  1911.                             {   titlebar = TRUE;
  1912.                             } else
  1913.                             {   titlebar = FALSE;
  1914.                             }
  1915.                             ShowTitle(ScreenPtr, titlebar);
  1916.                         break;
  1917.                         default:
  1918.                         break;
  1919.                         }
  1920.                     break;
  1921.                     case MN_HELP:
  1922.                         switch(ITEMNUM(code))
  1923.                         {
  1924.                         case IN_GAME_SUMMARY:
  1925.                             summarywindow();
  1926.                         break;
  1927.                         case IN_HELP_1:
  1928.                             docwindow(1);
  1929.                         break;
  1930.                         case IN_HELP_2:
  1931.                             docwindow(2);
  1932.                         break;
  1933.                         case IN_HELP_3:
  1934.                             docwindow(3);
  1935.                         break;
  1936.                         case IN_HELP_4:
  1937.                             docwindow(4);
  1938.                         break;
  1939.                         case IN_ABOUT:
  1940.                             helpabout();
  1941.                         break;
  1942.                         default:
  1943.                         break;
  1944.                         }
  1945.                     break;
  1946.                     default:
  1947.                     break;
  1948.                     }
  1949.                     code = ItemPtr->NextSelect;
  1950.                 }
  1951.             break;
  1952.             default: // IDCMP_MENUVERIFY, etc.
  1953.             break;
  1954. }   }   }   }
  1955.  
  1956. MODULE void newgame(void)
  1957. {   SLONG whichhero, whichjarl, whichmonster, whichcountry, whichslot,
  1958.           whichtreasure, whichsord;
  1959.  
  1960.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
  1961.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
  1962.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
  1963.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
  1964.      OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP,    IN_GAME_SUMMARY, NOSUB));
  1965.  
  1966.     pathname[0] = 0;
  1967.  
  1968.     /* 0. SET UP
  1969.  
  1970.     "Divide the counters into four piles, keeping the heroes separate.
  1971.     The four piles, all face down, should be: monsters of all sorts,
  1972.     jarls, magic weapons [(swords)], and magic treasures.
  1973.  
  1974.     Each player picks a hero counter to represent him or her in the game.
  1975.     Players roll dice if two or more people want the same counter, and
  1976.     high roll chooses first." */
  1977.  
  1978.     reset_images();
  1979.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  1980.     {   hero[whichhero].strength  = HERO_STRENGTH;
  1981.         hero[whichhero].moves     = HERO_MOVES;
  1982.         hero[whichhero].name      = trueheroname[whichhero];
  1983.         hero[whichhero].attacking =
  1984.         hero[whichhero].defending =
  1985.         hero[whichhero].alive     = FALSE;
  1986.         hero[whichhero].verydead  = TRUE;
  1987.         hero[whichhero].glory     =
  1988.         hero[whichhero].luck      =
  1989.         hero[whichhero].wealth    = 0;
  1990.         hero[whichhero].rune      = -1;
  1991.         deselect_hero(whichhero, FALSE);
  1992.         remove_hero(whichhero, FALSE);
  1993.     }
  1994.     for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  1995.     {   jarl[whichjarl].hero      = -1;
  1996.         jarl[whichjarl].wealth    = 0;
  1997.         jarl[whichjarl].attacking =
  1998.         jarl[whichjarl].defending =
  1999.         jarl[whichjarl].alive     =
  2000.         jarl[whichjarl].taken     = FALSE;
  2001.         deselect_jarl(whichjarl, FALSE);
  2002.         remove_jarl(whichjarl, FALSE);
  2003.     }
  2004.     for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  2005.     {   monster[whichmonster].alive = FALSE;
  2006.         monster[whichmonster].taken = FALSE;
  2007.         deselect_monster(whichmonster, FALSE);
  2008.         remove_monster(whichmonster, FALSE);
  2009.     }
  2010.     for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  2011.     {   remove_treasure(whichtreasure, FALSE);
  2012.         treasure[whichtreasure].taken         = FALSE;
  2013.         treasure[whichtreasure].possessor     =
  2014.         treasure[whichtreasure].possessortype =
  2015.         treasure[whichtreasure].where         = -1;
  2016.     }
  2017.     for (whichsord = 0; whichsord <= SORDS; whichsord++)
  2018.     {   remove_sord(whichsord, FALSE);
  2019.         sord[whichsord].taken         = FALSE;
  2020.         sord[whichsord].possessor     =
  2021.         sord[whichsord].possessortype =
  2022.         sord[whichsord].where         = -1;
  2023.     }
  2024.  
  2025.     for (whichcountry = 0; whichcountry <= 65; whichcountry++)
  2026.     {   world[whichcountry].hero = -1;
  2027.         world[whichcountry].is   = FALSE;
  2028.         for (whichslot = 0; whichslot <= SLOTS; whichslot++)
  2029.         {   world[whichcountry].slot[whichslot] = FALSE;
  2030.     }   }
  2031.  
  2032.     screenoff();
  2033.     SetRast(MainWindowPtr->RPort, BLACK);
  2034.     darken();
  2035.     drawmap();
  2036.     screenon();
  2037.  
  2038.     /* "Each player then picks a magic sword at random from the face-down
  2039.     pile. Magic swords will not be given out again in the game and so all
  2040.     of the left-over magic swords are put aside until the next game." */
  2041.  
  2042.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2043.     {   if (hero[whichhero].control != NONE)
  2044.         {   /* "Heroes begin the game in a randomly determined area (found in the
  2045.             same manner as monsters are placed). This area should be noted on the
  2046.             record sheet, as it is sometimes necessary to know a hero's home
  2047.             country." */
  2048.             newhero(whichhero, TRUE);
  2049.     }   }
  2050.  
  2051.     place_monsters();
  2052.     place_jarls();
  2053.     refreshcounters();
  2054.  
  2055.     turn = 1;
  2056.     faxirides = 3;
  2057. }
  2058.  
  2059. MODULE void clearkybd(void)
  2060. {   struct IntuiMessage* MsgPtr;
  2061.  
  2062.     while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2063.         GT_ReplyIMsg(MsgPtr);
  2064. }
  2065.  
  2066. MODULE void titlescreen(void)
  2067. {   AUTO    FLAG                 done;
  2068.     AUTO    SLONG                whichhero;
  2069.     AUTO    struct IntuiMessage* MsgPtr;
  2070.     AUTO    ULONG                class;
  2071.     AUTO    UWORD                code, qual;
  2072.     AUTO    struct Gadget*       addr;
  2073.     AUTO    struct MenuItem*     ItemPtr;
  2074.     AUTO    TEXT                 sgtext[40 + 1];
  2075.  
  2076.     loaded   =
  2077.     gameover = FALSE;
  2078.  
  2079.      OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
  2080.      OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
  2081.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
  2082.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
  2083.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_HELP,    IN_GAME_SUMMARY, NOSUB));
  2084.  
  2085.     SetWindowTitles(MainWindowPtr, (UBYTE *) -1, TITLEBAR); // this is not copied, it is a pointer
  2086.  
  2087.     clearscreen();
  2088.     drawlogo();
  2089.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2090.     {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2091.     }
  2092.     GT_SetGadgetAttrs(SpeedGadgetPtr,    MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2093.     GT_SetGadgetAttrs(AdvancedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2094.     RefreshGadgets(GListPtr, MainWindowPtr, NULL);
  2095.  
  2096.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2097.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2098.     {   SetAPen(MainWindowPtr->RPort, BLACK);
  2099.         Move(MainWindowPtr->RPort, 212 + 1, 208 + TBSIZE + (whichhero * 13) + 1);
  2100.         Text(MainWindowPtr->RPort, cycleheroname[whichhero], 10);
  2101.         Move(MainWindowPtr->RPort, 212 + 1 + (cycleheropos[whichhero] * 8), 208 + TBSIZE + (whichhero * 13) + 1 + 1);
  2102.         Text(MainWindowPtr->RPort, "_", 1);
  2103.         if (DisplayDepth >= DEPTH)
  2104.         {   SetAPen(MainWindowPtr->RPort, 136 + whichhero);
  2105.         } else
  2106.         {   SetAPen(MainWindowPtr->RPort, WHITE);
  2107.         }
  2108.         Move(MainWindowPtr->RPort, 212, 208 + TBSIZE + (whichhero * 13));
  2109.         Text(MainWindowPtr->RPort, cycleheroname[whichhero], 10);
  2110.         Move(MainWindowPtr->RPort, 212 + (cycleheropos[whichhero] * 8), 208 + TBSIZE + (whichhero * 13) + 1);
  2111.         Text(MainWindowPtr->RPort, "_", 1);
  2112.     }
  2113.  
  2114.     strcpy(sgtext, GetCatalogStr(li.li_Catalog, MSG_MESSAGE_DELAY, "Message Delay:"));
  2115.     SetAPen(MainWindowPtr->RPort, BLACK);
  2116.     Move(MainWindowPtr->RPort, 292 - (strlen(sgtext) * 8) + 1, 305 + TBSIZE + 1);
  2117.     Text(MainWindowPtr->RPort, sgtext, strlen(sgtext));
  2118.     SetAPen(MainWindowPtr->RPort, WHITE);
  2119.     Move(MainWindowPtr->RPort, 292 - (strlen(sgtext) * 8), 305 + TBSIZE);
  2120.     Text(MainWindowPtr->RPort, sgtext, strlen(sgtext));
  2121.  
  2122.     strcpy(sgtext, GetCatalogStr(li.li_Catalog, MSG_ADVANCED_MODE, "Advanced Mode?"));
  2123.     SetAPen(MainWindowPtr->RPort, BLACK);
  2124.     Move(MainWindowPtr->RPort, 292 - (strlen(sgtext) * 8) + 1, 329 + TBSIZE + 1);
  2125.     Text(MainWindowPtr->RPort, sgtext, strlen(sgtext));
  2126.     SetAPen(MainWindowPtr->RPort, WHITE);
  2127.     Move(MainWindowPtr->RPort, 292 - (strlen(sgtext) * 8), 329 + TBSIZE);
  2128.     Text(MainWindowPtr->RPort, sgtext, strlen(sgtext));
  2129.     if (cliload)
  2130.     {   if (loadgame(FALSE))
  2131.         {   loaded = TRUE;
  2132.         } else
  2133.         {   cliload = FALSE;
  2134.     }   }
  2135.  
  2136.     if (!cliload)
  2137.     {   done = FALSE;
  2138.         do
  2139.         {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  2140.             while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2141.             {   addr  = (struct Gadget *) MsgPtr->IAddress;
  2142.                 class = MsgPtr->Class;
  2143.                 code  = MsgPtr->Code;
  2144.                 qual  = MsgPtr->Qualifier;
  2145.                 GT_ReplyIMsg(MsgPtr);
  2146.                 switch (class)
  2147.                 {
  2148.                 case IDCMP_RAWKEY:
  2149.                     if (!(qual & IEQUALIFIER_REPEAT))
  2150.                     {   switch (code)
  2151.                         {
  2152.                         case SCAN_F1:
  2153.                             cycle(0, qual);
  2154.                         break;
  2155.                         case SCAN_F2:
  2156.                             cycle(1, qual);
  2157.                         break;
  2158.                         case SCAN_F3:
  2159.                             cycle(2, qual);
  2160.                         break;
  2161.                         case SCAN_F4:
  2162.                             cycle(3, qual);
  2163.                         break;
  2164.                         case SCAN_F5:
  2165.                             cycle(4, qual);
  2166.                         break;
  2167.                         case SCAN_F6:
  2168.                             cycle(5, qual);
  2169.                         break;
  2170.                         case HELP:
  2171.                             helpabout();
  2172.                         break;
  2173.                         case SCAN_LEFT:
  2174.                             if (speed > 0)
  2175.                             {   if
  2176.                                 (   (qual & IEQUALIFIER_LSHIFT)
  2177.                                  || (qual & IEQUALIFIER_RSHIFT)
  2178.                                  || (qual & IEQUALIFIER_LALT)
  2179.                                  || (qual & IEQUALIFIER_RALT)
  2180.                                  || (qual & IEQUALIFIER_CONTROL)
  2181.                                 )
  2182.                                 {   speed = 0;
  2183.                                 } else speed--;
  2184.                                 GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GTSL_Level, speed, TAG_DONE);
  2185.                             }
  2186.                         break;
  2187.                         case SCAN_RIGHT:
  2188.                             if (speed < 6)
  2189.                             {   if
  2190.                                 (   (qual & IEQUALIFIER_LSHIFT)
  2191.                                  || (qual & IEQUALIFIER_RSHIFT)
  2192.                                  || (qual & IEQUALIFIER_LALT)
  2193.                                  || (qual & IEQUALIFIER_RALT)
  2194.                                  || (qual & IEQUALIFIER_CONTROL)
  2195.                                 )
  2196.                                 {   speed = 6;
  2197.                                 } else speed++;
  2198.                                 GT_SetGadgetAttrs(SpeedGadgetPtr, MainWindowPtr, NULL, GTSL_Level, speed, TAG_DONE);
  2199.                             }
  2200.                         break;
  2201.                         default:
  2202.                         break;
  2203.                     }   }
  2204.                 break;
  2205.                 case IDCMP_VANILLAKEY:
  2206.                     code = toupper(code);
  2207.                     switch(code)
  2208.                     {
  2209.                     case ' ':
  2210.                     case 13: // Return or Enter
  2211.                         done = TRUE;
  2212.                     break;
  2213.                     case 27: // Escape
  2214.                         cleanexit(EXIT_SUCCESS);
  2215.                     break;
  2216.                     case '1':
  2217.                     case 'B':
  2218.                     case '!':
  2219.                         cycle(0, qual);
  2220.                     break;
  2221.                     case '2':
  2222.                     case 'U':
  2223.                     case '@':
  2224.                         cycle(1, qual);
  2225.                     break;
  2226.                     case '3':
  2227.                     case 'E':
  2228.                     case '#':
  2229.                         cycle(2, qual);
  2230.                     break;
  2231.                     case '4':
  2232.                     case 'R':
  2233.                     case '$':
  2234.                         cycle(3, qual);
  2235.                     break;
  2236.                     case '5':
  2237.                     case 'S':
  2238.                     case '%':
  2239.                         cycle(4, qual);
  2240.                     break;
  2241.                     case '6':
  2242.                     case 'T':
  2243.                     case '^':
  2244.                         cycle(5, qual);
  2245.                     break;
  2246.                     default:
  2247.                     break;
  2248.                     }
  2249.                 break;
  2250.                 case IDCMP_MENUPICK:
  2251.                     while (code != MENUNULL)
  2252.                     {   ItemPtr = ItemAddress(MenuPtr, code);
  2253.  
  2254.                         switch (MENUNUM(code))
  2255.                         {
  2256.                         case MN_PROJECT:
  2257.                             switch (ITEMNUM(code))
  2258.                             {
  2259.                             case IN_NEW:
  2260.                                 done = TRUE;
  2261.                             break;
  2262.                             case IN_OPEN:
  2263.                                 if (loadgame(TRUE))
  2264.                                 {   done = TRUE;
  2265.                                     loaded = TRUE;
  2266.                                 }
  2267.                             break;
  2268.                             case IN_QUIT:
  2269.                                 cleanexit(EXIT_SUCCESS);
  2270.                             break;
  2271.                             default:
  2272.                                 // IN_SAVE, IN_SAVEAS
  2273.                             break;
  2274.                             }
  2275.                         break;
  2276.                         case MN_SETTINGS:
  2277.                             switch(ITEMNUM(code))
  2278.                             {
  2279.                             case IN_SHOW_TITLEBAR:
  2280.                                 if (ItemPtr->Flags & CHECKED)
  2281.                                 {   titlebar = TRUE;
  2282.                                 } else
  2283.                                 {   titlebar = FALSE;
  2284.                                 }
  2285.                                 ShowTitle(ScreenPtr, titlebar);
  2286.                             break;
  2287.                             default:
  2288.                             break;
  2289.                             }
  2290.                         break;
  2291.                         case MN_HELP:
  2292.                             switch(ITEMNUM(code))
  2293.                             {
  2294.                             case IN_HELP_1:
  2295.                                 docwindow(1);
  2296.                             break;
  2297.                             case IN_HELP_2:
  2298.                                 docwindow(2);
  2299.                             break;
  2300.                             case IN_HELP_3:
  2301.                                 docwindow(3);
  2302.                             break;
  2303.                             case IN_HELP_4:
  2304.                                 docwindow(4);
  2305.                             break;
  2306.                             case IN_ABOUT:
  2307.                                 helpabout();
  2308.                             break;
  2309.                             default:
  2310.                             break;
  2311.                             }
  2312.                         break;
  2313.                         default:
  2314.                         break;
  2315.                         }
  2316.                         code = ItemPtr->NextSelect;
  2317.                     }
  2318.                 break;
  2319.                 case IDCMP_MOUSEBUTTONS:
  2320.                     if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
  2321.                     {   done = TRUE;
  2322.                     }
  2323.                 break;
  2324.                 case IDCMP_REFRESHWINDOW:
  2325.                     GT_BeginRefresh(MainWindowPtr);
  2326.                     GT_EndRefresh(MainWindowPtr, TRUE);
  2327.                 break;
  2328.                 case IDCMP_GADGETUP:
  2329.                     if (addr == SpeedGadgetPtr)
  2330.                     {   speed = code;
  2331.                     } elif (addr == AdvancedGadgetPtr)
  2332.                     {   if (AdvancedGadgetPtr->Flags & GFLG_SELECTED)
  2333.                         {   advanced = TRUE;
  2334.                             monsters = 30;
  2335.                             treasures = 5;
  2336.                         } else
  2337.                         {   advanced = FALSE;
  2338.                             monsters = 26;
  2339.                             treasures = 3;
  2340.                     }   }
  2341.                     else
  2342.                     {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2343.                         {   if (addr == CycleGadgetPtr[whichhero])
  2344.                             {   hero[whichhero].control = code;
  2345.                                 break;
  2346.                     }   }   }
  2347.                 break;
  2348.                 case IDCMP_CLOSEWINDOW:
  2349.                     cleanexit(EXIT_SUCCESS);
  2350.                 break;
  2351.                 default:
  2352.                     ; /* IDCMP_INTUITICKS */
  2353.                 break;
  2354.             }   }
  2355.             if (done)
  2356.             {   done = FALSE;
  2357.                 for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2358.                 {   if (hero[whichhero].control != NONE)
  2359.                     {   done = TRUE;
  2360.                         break;
  2361.                 }   }
  2362.                 if (!done)
  2363.                 {   ; // DisplayBeep(ScreenPtr); // no heroes active
  2364.             }   }
  2365.         } while (!done);
  2366.     }
  2367.  
  2368.     cliload = FALSE;
  2369.     if (!loaded)
  2370.     {   for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2371.         {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2372.         }
  2373.         GT_SetGadgetAttrs(SpeedGadgetPtr,    MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2374.         GT_SetGadgetAttrs(AdvancedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2375. }   }
  2376.  
  2377. MODULE void helpabout(void)
  2378. {   SBYTE                line;
  2379.     FLAG                 done          = FALSE;
  2380.     ULONG                class;
  2381.     UWORD                code, qual;
  2382.     struct IntuiMessage* MsgPtr;
  2383.  
  2384.     if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
  2385.         WA_Left,          (SCREENXPIXEL / 2) - (ABOUTXPIXEL / 2),
  2386.         WA_Top,           (SCREENYPIXEL / 2) - (ABOUTYPIXEL / 2),
  2387.         WA_Width,         ABOUTXPIXEL,
  2388.         WA_Height,        ABOUTYPIXEL,
  2389.         WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  2390.         WA_Title,         abouttitle,
  2391.         WA_Gadgets,       NULL,
  2392.         WA_CustomScreen,  ScreenPtr,
  2393.         WA_DragBar,       TRUE,
  2394.         WA_CloseGadget,   TRUE,
  2395.         WA_NoCareRefresh, TRUE,
  2396.         WA_Activate,      TRUE,
  2397.         WA_GimmeZeroZero, TRUE,
  2398.     TAG_DONE)))
  2399.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open About... window!\0", 24);
  2400.         cleanexit(EXIT_FAILURE);
  2401.     } else
  2402.     {   fillwindow(HelpWindowPtr);
  2403.         SetDrMd(HelpWindowPtr->RPort, JAM1);
  2404.         SetAPen(HelpWindowPtr->RPort, BLACK);
  2405.         for (line = 0; line <= ABOUTLINES; line++)
  2406.         {   Move(HelpWindowPtr->RPort, about[line].x + 1, about[line].y + 1);
  2407.             Text(HelpWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
  2408.         }
  2409.         SetAPen(HelpWindowPtr->RPort, WHITE);
  2410.         for (line = 0; line <= ABOUTLINES; line++)
  2411.         {   Move(HelpWindowPtr->RPort, about[line].x, about[line].y);
  2412.             Text(HelpWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
  2413.         }
  2414.         drawabout();
  2415.         if (aga)
  2416.         {   boingball();
  2417.         }
  2418.  
  2419.         while (!done)
  2420.         {   if (aga)
  2421.             {   DrawGels();
  2422.             } else
  2423.             {   Wait(1L << HelpWindowPtr->UserPort->mp_SigBit);
  2424.             }
  2425.             while (MsgPtr = (struct IntuiMessage *) GetMsg(HelpWindowPtr->UserPort))
  2426.             {   class = MsgPtr->Class;
  2427.                 code  = MsgPtr->Code;
  2428.                 qual  = MsgPtr->Qualifier;
  2429.                 ReplyMsg((struct Message *) MsgPtr);
  2430.                 switch (class)
  2431.                 {
  2432.                 case IDCMP_CLOSEWINDOW:
  2433.                     done = TRUE;
  2434.                 break;
  2435.                 case IDCMP_RAWKEY:
  2436.                     if (!(qual & IEQUALIFIER_REPEAT) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
  2437.                     {   if
  2438.                         (   code == ESCAPE
  2439.                          && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2440.                         )
  2441.                         {   cleanexit(EXIT_SUCCESS);
  2442.                         } else
  2443.                         {   done = TRUE;
  2444.                     }   }
  2445.                 break;
  2446.                 default:
  2447.                 break;
  2448.         }   }   }
  2449.  
  2450.         if (aga)
  2451.         {   unboingball();
  2452.         }
  2453.         CloseWindow(HelpWindowPtr);
  2454.         HelpWindowPtr = NULL;
  2455.         clearkybd();
  2456. }   }
  2457.  
  2458. MODULE void resettime(void)
  2459. {   struct timerequest* TimerIORequestPtr;
  2460.     struct timeval      timeval;
  2461.  
  2462.     if (!(TimerIORequestPtr = (struct timerequest *) AllocVec(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR)))
  2463.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Out of memory!\0", 24);
  2464.         cleanexit(EXIT_FAILURE);
  2465.     }
  2466.     if (OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) TimerIORequestPtr, 0))
  2467.     {   FreeVec(TimerIORequestPtr);
  2468.         DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open timer.device!\0", 24);
  2469.         cleanexit(EXIT_FAILURE);
  2470.     }
  2471.     TimerBase = (struct Library *) TimerIORequestPtr->tr_node.io_Device;
  2472.     GetSysTime(&timeval);
  2473.     srand((UWORD) timeval.tv_micro);
  2474.     // no need to abort timer I/O requests, as we never send any
  2475.     CloseDevice((struct IORequest *) TimerIORequestPtr);
  2476.     FreeVec(TimerIORequestPtr);
  2477. }
  2478.  
  2479. MODULE FLAG loadgame(FLAG aslwindow)
  2480. {   SLONG offset = 12, whichhero, whichjarl, whichmonster, whichcountry,
  2481.           whichslot, whichtreasure, whichsord;
  2482.     TEXT  newpathname[255];
  2483.     BPTR  FileHandle /* = NULL */ ;
  2484.     FLAG  ok;
  2485.  
  2486.     if (aslwindow)
  2487.     {   if
  2488.         (   AslRequestTags
  2489.             (    ASLRqPtr,
  2490.                  ASL_Hail, GetCatalogStr(li.li_Catalog, MSG_LOAD_GAME, "Load Game"),
  2491.                  ASL_FuncFlags, FILF_PATGAD,
  2492.                  TAG_DONE
  2493.             )
  2494.          && *(ASLRqPtr->rf_File)
  2495.         )
  2496.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  2497.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  2498.             ok = TRUE;
  2499.         } else
  2500.         {   ok = FALSE;
  2501.     }   }
  2502.     else
  2503.     {   ok = TRUE;
  2504.         strcpy(newpathname, pathname);
  2505.     }
  2506.  
  2507.     if (ok)
  2508.     {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_LOADING, "Loading"));
  2509.         strcat(saystring, " ");
  2510.         strcat(saystring, newpathname);
  2511.         strcat(saystring, "...");
  2512.         say(LOWER);
  2513.  
  2514.         if (!(FileHandle = Open(newpathname, MODE_OLDFILE)))
  2515.         {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_OPEN, "Can't open"));
  2516.             strcat(saystring, " ");
  2517.             strcat(saystring, newpathname);
  2518.             strcat(saystring, " ");
  2519.             strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FOR_READING, "for reading"));
  2520.             strcat(saystring, "!");
  2521.             say(LOWER);
  2522.             return(FALSE);
  2523.         }
  2524.  
  2525.         // read file
  2526.         if (Read(FileHandle, IOBuffer, SAVELENGTH) != SAVELENGTH)
  2527.         {   Close(FileHandle);
  2528.             // FileHandle = NULL;
  2529.             strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_READ_FROM, "Can't read from"));
  2530.             strcat(saystring, " ");
  2531.             strcat(saystring, newpathname);
  2532.             strcat(saystring, "!");
  2533.             say(LOWER);
  2534.             return(FALSE);
  2535.         }
  2536.  
  2537.         if (strcmp(IOBuffer, "SAGA 1.4 "))
  2538.         {   Close(FileHandle);
  2539.             // FileHandle = NULL;
  2540.             strcpy(saystring, newpathname);
  2541.             strcat(saystring, " ");
  2542.             strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_I_N_A_V_S_G_F, "is not a valid saved game file"));
  2543.             strcat(saystring, "!");
  2544.             say(LOWER);
  2545.             return(FALSE);
  2546.         }
  2547.         turn      = (SLONG) ((SBYTE) IOBuffer[10]);
  2548.         faxirides = (SLONG) ((SBYTE) IOBuffer[11]);
  2549.  
  2550.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2551.         {   hero[whichhero].control   = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2552.             hero[whichhero].alive     = (FLAG)  ((SBYTE) IOBuffer[offset++] );
  2553.             hero[whichhero].verydead  = (FLAG)  ((SBYTE) IOBuffer[offset++] );
  2554.             hero[whichhero].moves     = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2555.             hero[whichhero].god       = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2556.             hero[whichhero].rune      = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2557.             hero[whichhero].where     = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2558.             hero[whichhero].homewhere = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2559.             hero[whichhero].promoted  = (SLONG) ((SBYTE) IOBuffer[offset++] );
  2560.             hero[whichhero].wounded   = (FLAG)  ((SBYTE) IOBuffer[offset++] );
  2561.             hero[whichhero].wealth    = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
  2562.             hero[whichhero].glory     = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
  2563.             hero[whichhero].luck      = (SLONG) ((IOBuffer[offset++] * 256) + IOBuffer[offset++]);
  2564.             hero[whichhero].sea       = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2565.             hero[whichhero].loseturn  = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2566.             hero[whichhero].maidens   = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2567.         }
  2568.         for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  2569.         {   jarl[whichjarl].where     = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2570.             jarl[whichjarl].homewhere = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2571.             jarl[whichjarl].face      = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2572.             jarl[whichjarl].hero      = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2573.             jarl[whichjarl].taken     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2574.             jarl[whichjarl].sea       = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2575.             jarl[whichjarl].loseturn  = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2576.             jarl[whichjarl].alive     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2577.         }
  2578.         for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  2579.         {   monster[whichmonster].taken    = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2580.             monster[whichmonster].alive    = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2581.             monster[whichmonster].where    = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2582.             monster[whichmonster].wealth   = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2583.             monster[whichmonster].sea      = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2584.             offset++; // skip monster[].loseturn
  2585.         }
  2586.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  2587.         {   treasure[whichtreasure].taken         = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2588.             treasure[whichtreasure].possessor     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2589.             treasure[whichtreasure].possessortype = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2590.             treasure[whichtreasure].where         = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2591.         }
  2592.         for (whichsord = 0; whichsord <= SORDS; whichsord++)
  2593.         {   sord[whichsord].taken         = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2594.             sord[whichsord].possessor     = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2595.             sord[whichsord].possessortype = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2596.             sord[whichsord].where         = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2597.         }
  2598.         for (whichcountry = 0; whichcountry <= 35; whichcountry++)
  2599.         {   world[whichcountry].hero = (SLONG) ((SBYTE) IOBuffer[offset++]);
  2600.             world[whichcountry].is   = (FLAG)  ((SBYTE) IOBuffer[offset++]);
  2601.         }
  2602.         advanced = (FLAG) ((SBYTE) IOBuffer[offset]); // ++ is not needed
  2603.         // no need to read version string
  2604.         Close(FileHandle);
  2605.         // FileHandle = NULL;
  2606.  
  2607.         strcpy(pathname, newpathname);
  2608.  
  2609.         if (advanced)
  2610.         {   treasures = 5;
  2611.             monsters = 30;
  2612.         } else
  2613.         {   treasures = 3;
  2614.             monsters = 26;
  2615.         }
  2616.  
  2617.         screenoff();
  2618.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2619.         {   GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2620.         }
  2621.         GT_SetGadgetAttrs(SpeedGadgetPtr,    MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2622.         GT_SetGadgetAttrs(AdvancedGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2623.         screenon();
  2624.  
  2625.         for (whichcountry = 0; whichcountry <= 65; whichcountry++)
  2626.         {   for (whichslot = 0; whichslot <= SLOTS; whichslot++)
  2627.             {   world[whichcountry].slot[whichslot] = FALSE;
  2628.         }   }
  2629.  
  2630.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2631.         {   if (hero[whichhero].promoted == -1)
  2632.             {   hero[whichhero].name     = trueheroname[whichhero];
  2633.                 hero[whichhero].strength = HERO_STRENGTH;
  2634.                 hero[whichhero].moves    = HERO_MOVES;
  2635.             } else
  2636.             {   hero[whichhero].name     = jarl[hero[whichhero].promoted].name;
  2637.                 hero[whichhero].strength = jarl[hero[whichhero].promoted].strength;
  2638.                 hero[whichhero].moves    = jarl[hero[whichhero].promoted].moves;
  2639.             }
  2640.             deselect_hero(whichhero, FALSE);
  2641.             if (hero[whichhero].alive)
  2642.             {   move_hero(whichhero, FALSE);
  2643.             } else
  2644.             {   remove_hero(whichhero, FALSE);
  2645.         }   }
  2646.  
  2647.         for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  2648.         {   jarl[whichjarl].recruitable = FALSE;
  2649.             if (jarl[whichjarl].alive)
  2650.             {   if (jarl[whichjarl].face == FACEUP)
  2651.                 {   revealjarl(whichjarl, FALSE);
  2652.                 } else
  2653.                 {   assert(jarl[whichjarl].face == FACEDOWN);
  2654.                     hidejarl(whichjarl, FALSE);
  2655.                 }
  2656.                 move_jarl(whichjarl, FALSE);
  2657.             } else
  2658.             {   remove_jarl(whichjarl, FALSE);
  2659.         }   }
  2660.  
  2661.         for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  2662.         {   if (monster[whichmonster].alive)
  2663.             {   move_monster(whichmonster, FALSE);
  2664.             } else
  2665.             {   remove_monster(whichmonster, FALSE);
  2666.         }   }
  2667.  
  2668.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  2669.         {   if (treasure[whichtreasure].possessor == -1)
  2670.             {   move_treasure(whichtreasure, FALSE);
  2671.         }   }
  2672.  
  2673.         for (whichsord = 0; whichsord <= SORDS; whichsord++)
  2674.         {   if (sord[whichsord].possessor == -1)
  2675.             {   move_sord(whichsord, FALSE);
  2676.         }   }
  2677.  
  2678.         SetRast(MainWindowPtr->RPort, BLACK);
  2679.         darken();
  2680.         drawmap();
  2681.         refreshcounters();
  2682.  
  2683.         if (faxirides == -1)
  2684.         {   faxirides = 0;
  2685.             treasure_disappear(FREYFAXI);
  2686.         }
  2687.  
  2688.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,          NOSUB));
  2689.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,         NOSUB));
  2690.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,         NOSUB));
  2691.         OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS,       NOSUB));
  2692.          OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP,    IN_GAME_SUMMARY, NOSUB));
  2693.  
  2694.         strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_LOADED, "Loaded"));
  2695.         strcat(saystring, " ");
  2696.         strcat(saystring, pathname);
  2697.         strcat(saystring, ".");
  2698.         say(LOWER);
  2699.         return(TRUE);
  2700. }   }
  2701.  
  2702. MODULE void savegame(FLAG saveas)
  2703. {   SLONG offset = 12, whichhero, whichjarl, whichmonster, whichcountry,
  2704.           whichtreasure, whichsord;
  2705.     FLAG  cont = TRUE;
  2706.     TEXT  newpathname[255];
  2707.     BPTR  FileHandle /* = NULL */ ;
  2708.  
  2709.     strcpy(newpathname, pathname);
  2710.     if (saveas || newpathname[0] == 0)
  2711.     {   if
  2712.         (   AslRequestTags
  2713.             (   ASLRqPtr,
  2714.                 ASL_Hail, GetCatalogStr(li.li_Catalog, MSG_SAVE_GAME, "Save Game"),
  2715.                 ASL_FuncFlags, FILF_PATGAD | FILF_SAVE,
  2716.                 TAG_DONE
  2717.             )
  2718.          && *(ASLRqPtr->rf_File) != 0
  2719.         )
  2720.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  2721.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  2722.         } else
  2723.         {   cont = FALSE;
  2724.     }   }
  2725.     if (!cont)
  2726.     {   return;
  2727.     }
  2728.  
  2729.     strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SAVING, "Saving"));
  2730.     strcat(saystring, " ");
  2731.     strcat(saystring, newpathname);
  2732.     strcat(saystring, "...");
  2733.     say(LOWER);
  2734.  
  2735.     if (!(FileHandle = Open(newpathname, MODE_NEWFILE)))
  2736.     {   strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_OPEN, "Can't open"));
  2737.         strcat(saystring, " ");
  2738.         strcat(saystring, newpathname);
  2739.         strcat(saystring, " ");
  2740.         strcat(saystring, GetCatalogStr(li.li_Catalog, MSG_FOR_WRITING, "for writing"));
  2741.         strcat(saystring, "!");
  2742.         say(LOWER);
  2743.         anykey();
  2744.         return;
  2745.     }
  2746.  
  2747.     /* write header
  2748.        SAGA 1.4 *#%
  2749.        012345678901
  2750.        where * is NULL byte and # is turn and % is faxi rides */
  2751.  
  2752.     strcpy(IOBuffer, "SAGA 1.4 ");
  2753.     IOBuffer[10] = (SBYTE) turn;
  2754.     IOBuffer[11] = (SBYTE) faxirides;
  2755.  
  2756.     for (whichhero = 0; whichhero <= HEROES; whichhero++)
  2757.     {   IOBuffer[offset++] = (SBYTE) hero[whichhero].control;
  2758.         IOBuffer[offset++] = (SBYTE) hero[whichhero].alive;
  2759.         IOBuffer[offset++] = (SBYTE) hero[whichhero].verydead;
  2760.         IOBuffer[offset++] = (SBYTE) hero[whichhero].moves;
  2761.         IOBuffer[offset++] = (SBYTE) hero[whichhero].god;
  2762.         IOBuffer[offset++] = (SBYTE) hero[whichhero].rune;
  2763.         IOBuffer[offset++] = (SBYTE) hero[whichhero].where;
  2764.         IOBuffer[offset++] = (SBYTE) hero[whichhero].homewhere;
  2765.         IOBuffer[offset++] = (SBYTE) hero[whichhero].promoted;
  2766.         IOBuffer[offset++] = (SBYTE) hero[whichhero].wounded;
  2767.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].wealth / 256);
  2768.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].wealth % 256);
  2769.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].glory  / 256);
  2770.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].glory  % 256);
  2771.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].luck   / 256);
  2772.         IOBuffer[offset++] = (UBYTE) (hero[whichhero].luck   % 256);
  2773.         IOBuffer[offset++] = (SBYTE) hero[whichhero].sea;
  2774.         IOBuffer[offset++] = (SBYTE) hero[whichhero].loseturn;
  2775.         IOBuffer[offset++] = (SBYTE) hero[whichhero].maidens;
  2776.     }
  2777.     for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  2778.     {   IOBuffer[offset++] = (SBYTE) jarl[whichjarl].where;
  2779.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].homewhere;
  2780.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].face;
  2781.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].hero;
  2782.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].taken;
  2783.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].sea;
  2784.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].loseturn;
  2785.         IOBuffer[offset++] = (SBYTE) jarl[whichjarl].alive;
  2786.     }
  2787.     for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  2788.     {   IOBuffer[offset++] = (SBYTE) monster[whichmonster].taken;
  2789.         IOBuffer[offset++] = (SBYTE) monster[whichmonster].alive;
  2790.         IOBuffer[offset++] = (SBYTE) monster[whichmonster].where;
  2791.         IOBuffer[offset++] = (SBYTE) monster[whichmonster].wealth;
  2792.         IOBuffer[offset++] = (SBYTE) monster[whichmonster].sea;
  2793.         IOBuffer[offset++] = (SBYTE) 0; // skip monster loseturn
  2794.     }
  2795.     for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  2796.     {   IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].taken;
  2797.         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].possessor;
  2798.         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].possessortype;
  2799.         IOBuffer[offset++] = (SBYTE) treasure[whichtreasure].where;
  2800.     }
  2801.     for (whichsord = 0; whichsord <= SORDS; whichsord++)
  2802.     {   IOBuffer[offset++] = (SBYTE) sord[whichsord].taken;
  2803.         IOBuffer[offset++] = (SBYTE) sord[whichsord].possessor;
  2804.         IOBuffer[offset++] = (SBYTE) sord[whichsord].possessortype;
  2805.         IOBuffer[offset++] = (SBYTE) sord[whichsord].where;
  2806.     }
  2807.     for (whichcountry = 0; whichcountry <= 35; whichcountry++)
  2808.     {   IOBuffer[offset++] = (SBYTE) world[whichcountry].hero;
  2809.         IOBuffer[offset++] = (SBYTE) world[whichcountry].is;
  2810.     }
  2811.     IOBuffer[offset++] = (SBYTE) advanced;
  2812.  
  2813. #ifdef EXTRAVERBOSE
  2814.     Printf("%ld bytes written.\n", offset);
  2815. #endif
  2816.  
  2817.     if (Write(FileHandle, IOBuffer, offset) != offset)
  2818.     {   Close(FileHandle);
  2819.         // FileHandle = NULL;
  2820.         strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_CANT_WRITE_TO, "Can't write to"));
  2821.         strcat(saystring, " ");
  2822.         strcat(saystring, newpathname);
  2823.         strcat(saystring, "!");
  2824.         say(LOWER);
  2825.         anykey();
  2826.         return;
  2827.     }
  2828.  
  2829.     /* write version string */
  2830.     Write(FileHandle, VERSION, strlen(VERSION));
  2831.  
  2832.     Close(FileHandle);
  2833.     // FileHandle = NULL;
  2834.  
  2835.     strcpy(pathname, newpathname);
  2836.  
  2837.     strcpy(saystring, GetCatalogStr(li.li_Catalog, MSG_SAVED, "Saved"));
  2838.     strcat(saystring, " ");
  2839.     strcat(saystring, pathname);
  2840.     strcat(saystring, ".");
  2841.     say(LOWER);
  2842.     // no need for anykey(), as there is one when we return anyway.
  2843. }
  2844.  
  2845. EXPORT void darken(void)
  2846. {   SLONG whichcountry, colour;
  2847.  
  2848.     for (whichcountry = 0; whichcountry <= 35; whichcountry++)
  2849.     {   if (whichcountry >= 9 && whichcountry <= 11)
  2850.         {   colour = whichcountry + 80;
  2851.         } else
  2852.         {   colour = whichcountry + 8;
  2853.         }
  2854.         if (world[whichcountry].is)
  2855.         {   SetRGB4(&ScreenPtr->ViewPort, colour, 12, 12, 12); // light grey ice
  2856.         } elif (world[whichcountry].hero != -1)
  2857.         {   SetRGB4
  2858.             (   &ScreenPtr->ViewPort,
  2859.                 colour,
  2860.                 herocolour[world[whichcountry].hero].red,
  2861.                 herocolour[world[whichcountry].hero].green,
  2862.                 herocolour[world[whichcountry].hero].blue
  2863.             );
  2864.         } else
  2865.         {   SetRGB4
  2866.             (   &ScreenPtr->ViewPort,
  2867.                 colour,
  2868.                 taxcolours[world[whichcountry].tax].red,
  2869.                 taxcolours[world[whichcountry].tax].green,
  2870.                 taxcolours[world[whichcountry].tax].blue
  2871.             );
  2872. }   }   }
  2873.  
  2874. MODULE SLONG checkcountry(WORD mousex, WORD mousey)
  2875. {   SLONG country;
  2876.  
  2877.     country = ReadPixel(MainWindowPtr->RPort, mousex, mousey);
  2878.  
  2879.     if (country == 80 || country == 81 || country == 91)
  2880.     {   country = 11; // Scandia
  2881.     } elif (country == 82 || country == 83)
  2882.     {   country = 30; // Pictland
  2883.     } elif (country == 84 || country == 85)
  2884.     {   country = 31; // Hebrides
  2885.     } elif (country == 89)
  2886.     {   country =  9; // Suder Gotland
  2887.     } elif (country == 90)
  2888.     {   country = 10; // Juteland
  2889.     } else
  2890.     {   country -= 8;
  2891.     }
  2892.  
  2893.     return(country);
  2894. }
  2895.  
  2896. MODULE void infowindow(SLONG countertype, SLONG whichcounter)
  2897. {   SLONG lines,
  2898.           leftlines     = 0,
  2899.           rightlines    = 0,
  2900.           oldwhichline,
  2901.           whichline,
  2902.           whichcountry,
  2903.           whichjarl,
  2904.           whichhero,
  2905.           whichtreasure,
  2906.           whichsord,
  2907.           wide,
  2908.           whichmonster;
  2909.     FLAG  counterrow    = FALSE,
  2910.           ok;
  2911.  
  2912.     if (countertype == HERO)
  2913.     {   sprintf(label[0],  "%s:", GetCatalogStr(li.li_Catalog, MSG_HERO_NAME,       "Hero Name"      ));
  2914.         sprintf(label[1],  "%s:", GetCatalogStr(li.li_Catalog, MSG_CONTROL,         "Control"        ));
  2915.         sprintf(label[2],  "%s:", GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
  2916.         sprintf(label[3],  "%s:", GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
  2917.         sprintf(label[4],  "%s:", GetCatalogStr(li.li_Catalog, MSG_GLORY,           "Glory"          ));
  2918.         sprintf(label[5],  "%s:", GetCatalogStr(li.li_Catalog, MSG_LUCK,            "Luck"           ));
  2919.         sprintf(label[6],  "%s:", GetCatalogStr(li.li_Catalog, MSG_WEALTH,          "Wealth"         ));
  2920.         sprintf(label[8],  "%s:", GetCatalogStr(li.li_Catalog, MSG_HOMELAND,        "Homeland"       ));
  2921.         sprintf(label[9],  "%s:", GetCatalogStr(li.li_Catalog, MSG_MAIDENS,         "Maidens"        ));
  2922.         sprintf(label[10], "%s:", GetCatalogStr(li.li_Catalog, MSG_RUNE,            "Rune"           ));
  2923.         sprintf(label[11], "%s:", GetCatalogStr(li.li_Catalog, MSG_SWORD,           "Sword"          ));
  2924.         sprintf(label[12], "%s:", GetCatalogStr(li.li_Catalog, MSG_STATUS,          "Status"         ));
  2925.         sprintf(label[13], "%s:", GetCatalogStr(li.li_Catalog, MSG_GOD,             "God"            ));
  2926.  
  2927.         /* If labels beyond [13] are desired, the labels[] array will of
  2928.         course to be redimensioned. */
  2929.  
  2930.         strcpy(line[LEFTSIDE][0], hero[whichcounter].name);
  2931.         if (hero[whichcounter].control == HUMAN)
  2932.         {   strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_HUMAN, "Human"));
  2933.         } else
  2934.         {   assert(hero[whichcounter].control == AMIGA);
  2935.             strcpy(line[LEFTSIDE][1], "Amiga");
  2936.         }
  2937.         sprintf
  2938.         (   line[LEFTSIDE][2], "%ld (%ld/%ld)",
  2939.             hero[whichcounter].strength,
  2940.             getstrength(HERO, whichcounter, FALSE),
  2941.             getstrength(HERO, whichcounter, TRUE)
  2942.         );
  2943.         sprintf
  2944.         (   line[LEFTSIDE][3], "%ld (%ld)",
  2945.             hero[whichcounter].moves,
  2946.             getusualmoves(HERO, whichcounter)
  2947.         );
  2948.         sprintf(line[LEFTSIDE][4], "%ld", hero[whichcounter].glory);
  2949.         sprintf(line[LEFTSIDE][5], "%ld", hero[whichcounter].luck);
  2950.         sprintf(line[LEFTSIDE][6], "%ld", hero[whichcounter].wealth);
  2951.         print_location(hero[whichcounter].where, 7);
  2952.         sprintf
  2953.         (   line[LEFTSIDE][8], "%s (%ld)",
  2954.             world[hero[whichcounter].homewhere].name,
  2955.             world[hero[whichcounter].homewhere].tax
  2956.         );
  2957.         sprintf(line[LEFTSIDE][9], "%ld", hero[whichcounter].maidens);
  2958.         if (hero[whichcounter].rune == -1)
  2959.         {   strcpy(line[LEFTSIDE][10], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  2960.         } else
  2961.         {   strcpy(line[LEFTSIDE][10], rune[hero[whichcounter].rune].name);
  2962.         }
  2963.         ok = FALSE;
  2964.         for (whichsord = 0; whichsord <= SORDS; whichsord++)
  2965.         {   if
  2966.             (   sord[whichsord].possessortype == HERO
  2967.              && sord[whichsord].possessor == whichcounter
  2968.             )
  2969.             {   ok = TRUE;
  2970.                 counterrow = TRUE;
  2971.                 strcpy(line[LEFTSIDE][11], sord[whichsord].name);
  2972.                 break; // for speed
  2973.         }   }
  2974.         if (!ok)
  2975.         {   strcpy(line[LEFTSIDE][11], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  2976.         }
  2977.  
  2978.         if (!hero[whichcounter].wounded)
  2979.         {   strcpy(line[LEFTSIDE][12], GetCatalogStr(li.li_Catalog, MSG_HEALTHY, "Healthy"));
  2980.         } else
  2981.         {   strcpy(line[LEFTSIDE][12], GetCatalogStr(li.li_Catalog, MSG_WOUNDED, "Wounded"));
  2982.         }
  2983.  
  2984.         switch (hero[whichcounter].god)
  2985.         {
  2986.         case ODIN:
  2987.             strcpy(line[LEFTSIDE][13], "Odin");
  2988.         break;
  2989.         case THOR:
  2990.             strcpy(line[LEFTSIDE][13], "Thor");
  2991.         break;
  2992.         case TYR:
  2993.             strcpy(line[LEFTSIDE][13], "Tyr");
  2994.         break;
  2995.         default:
  2996.             strcpy(line[LEFTSIDE][13], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  2997.         break;
  2998.         }
  2999.  
  3000.         print_paralyzed(hero[whichcounter].loseturn, 14);
  3001.            print_hagall(hero[whichcounter].hagall,   15);
  3002.               print_sea(hero[whichcounter].sea,      16);
  3003.            print_routed(hero[whichcounter].routed,   17);
  3004.         leftlines = 18; // counting from 1
  3005.  
  3006.         strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_RECRUITED_JARLS, "Recruited Jarls"));
  3007.         strcat(line[RIGHTSIDE][0], ":");
  3008.  
  3009.         whichline = oldwhichline = 1; // whichline always points to the NEXT line.
  3010.         for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  3011.         {   if (jarl[whichjarl].alive && jarl[whichjarl].hero == whichcounter)
  3012.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3013.                 strcat(line[RIGHTSIDE][whichline], jarl[whichjarl].name);
  3014.                 strcat(line[RIGHTSIDE][whichline], " (");
  3015.                 stcl_d(numberstring, jarl[whichjarl].strength);
  3016.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3017.                 strcat(line[RIGHTSIDE][whichline], "-");
  3018.                 stcl_d(numberstring, jarl[whichjarl].moves);
  3019.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3020.                 strcat(line[RIGHTSIDE][whichline], ")");
  3021.                 whichline++;
  3022.         }   }
  3023.         if (whichline == oldwhichline)
  3024.         {   strcpy(line[RIGHTSIDE][whichline], " ");
  3025.             strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3026.             whichline++;
  3027.         }
  3028.  
  3029.         strcpy(line[RIGHTSIDE][whichline], "");
  3030.         whichline++;
  3031.         strcpy(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_CONQUERED_KINGDOMS, "Conquered Kingdoms"));
  3032.         strcat(line[RIGHTSIDE][whichline], ":");
  3033.         whichline++;
  3034.  
  3035.         oldwhichline = whichline;
  3036.         for (whichcountry = 0; whichcountry <= 35; whichcountry++)
  3037.         {   if (world[whichcountry].hero == whichcounter)
  3038.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3039.                 strcat(line[RIGHTSIDE][whichline], world[whichcountry].name);
  3040.                 strcat(line[RIGHTSIDE][whichline], " (");
  3041.                 stcl_d(numberstring, world[whichcountry].tax);
  3042.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3043.                 strcat(line[RIGHTSIDE][whichline], ")");
  3044.                 whichline++;
  3045.         }   }
  3046.         if (whichline == oldwhichline)
  3047.         {   strcpy(line[RIGHTSIDE][whichline], " ");
  3048.             strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3049.             whichline++;
  3050.         }
  3051.  
  3052.         strcpy(line[RIGHTSIDE][whichline], "");
  3053.         whichline++;
  3054.         strcpy(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_MAGIC_TREASURES, "Magic Treasures"));
  3055.         strcat(line[RIGHTSIDE][whichline], ":");
  3056.         whichline++;
  3057.  
  3058.         oldwhichline = whichline;
  3059.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  3060.         {   if (treasure[whichtreasure].possessortype == HERO
  3061.              && treasure[whichtreasure].possessor     == whichcounter
  3062.             )
  3063.             {   counterrow = TRUE;
  3064.                 strcpy(line[RIGHTSIDE][whichline], " ");
  3065.                 strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
  3066.                 if (whichtreasure == FREYFAXI)
  3067.                 {   strcat(line[RIGHTSIDE][whichline], " (");
  3068.                     stcl_d(numberstring, faxirides);
  3069.                     strcat(line[RIGHTSIDE][whichline], numberstring);
  3070.                     strcat(line[RIGHTSIDE][whichline], " ");
  3071.                     if (faxirides != 1)
  3072.                     {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_RIDES2, "rides"));
  3073.                     } else
  3074.                     {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_RIDE,   "ride"));
  3075.                     }
  3076.                     strcat(line[RIGHTSIDE][whichline], ")");
  3077.                 }
  3078.                 whichline++;
  3079.         }   }
  3080.         if (whichline == oldwhichline)
  3081.         {   strcpy(line[RIGHTSIDE][whichline], " ");
  3082.             strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3083.             whichline++;
  3084.         }
  3085.  
  3086.         rightlines = whichline;
  3087.     } elif (countertype == MONSTER)
  3088.     {   sprintf(label[0], "%s:", GetCatalogStr(li.li_Catalog, MSG_MONSTER_NAME,    "Monster Name"   ));
  3089.         sprintf(label[1], "%s:", GetCatalogStr(li.li_Catalog, MSG_MONSTER_SPECIES, "Monster Species"));
  3090.         sprintf(label[2], "%s:", GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
  3091.         sprintf(label[3], "%s:", GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
  3092.         sprintf(label[4], "%s:", GetCatalogStr(li.li_Catalog, MSG_WEALTH,          "Wealth"         ));
  3093.         sprintf(label[8], "%s?", GetCatalogStr(li.li_Catalog, MSG_TREASURE,        "Treasure"       ));
  3094.  
  3095.         strcpy(line[LEFTSIDE][0], monster[whichcounter].name);
  3096.         strcpy(line[LEFTSIDE][1], monstertypes[monster[whichcounter].species]);
  3097.         sprintf
  3098.         (   line[LEFTSIDE][2],
  3099.             "%ld (%ld/%ld)",
  3100.             monster[whichcounter].strength,
  3101.             getstrength(MONSTER, whichcounter, FALSE),
  3102.             getstrength(MONSTER, whichcounter, TRUE)
  3103.         );
  3104.         sprintf
  3105.         (   line[LEFTSIDE][3],
  3106.             "%ld (%ld)",
  3107.             monster[whichcounter].moves,
  3108.             getusualmoves(MONSTER, whichcounter)
  3109.         );
  3110.         sprintf(line[LEFTSIDE][4], "%ld", monster[whichcounter].wealth);
  3111.         print_location(monster[whichcounter].where, 5);
  3112.         print_hagall(monster[whichcounter].hagall, 6);
  3113.         print_sea(monster[whichcounter].sea, 7);
  3114.         ok = FALSE;
  3115.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  3116.         {   if
  3117.             (   treasure[whichtreasure].possessortype == MONSTER
  3118.              && treasure[whichtreasure].possessor == whichcounter
  3119.             )
  3120.             {   ok = TRUE;
  3121.                 break;
  3122.         }   }
  3123.         if (ok)
  3124.         {   strcpy(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
  3125.         } else
  3126.         {   strcpy(line[LEFTSIDE][8], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
  3127.         }
  3128.  
  3129.         leftlines = 9; // counting from 1
  3130.         rightlines = 0;
  3131.     } elif (countertype == JARL)
  3132.     {   sprintf(label[0], "%s:", GetCatalogStr(li.li_Catalog, MSG_JARL_NAME,       "Jarl Name"      ));
  3133.         sprintf(label[1], "%s:", GetCatalogStr(li.li_Catalog, MSG_HERO,            "Hero"           ));
  3134.         sprintf(label[2], "%s:", GetCatalogStr(li.li_Catalog, MSG_COMBAT_STRENGTH, "Combat Strength"));
  3135.         sprintf(label[3], "%s:", GetCatalogStr(li.li_Catalog, MSG_MOVEMENT_FACTOR, "Movement Factor"));
  3136.         sprintf(label[4], "%s:", GetCatalogStr(li.li_Catalog, MSG_WEALTH,          "Wealth"         ));
  3137.         sprintf(label[6], "%s:", GetCatalogStr(li.li_Catalog, MSG_HOMELAND,        "Homeland"       ));
  3138.         sprintf(label[7], "%s:", GetCatalogStr(li.li_Catalog, MSG_SWORD,           "Sword"          ));
  3139.  
  3140.         if (jarl[whichcounter].face == FACEUP)
  3141.         {   strcpy(line[LEFTSIDE][0], jarl[whichcounter].name);
  3142.         } else
  3143.         {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
  3144.         }
  3145.         if (jarl[whichcounter].hero == -1)
  3146.         {   strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING_NONE, "None"));
  3147.         } else
  3148.         {   strcpy(line[LEFTSIDE][1], hero[jarl[whichcounter].hero].name);
  3149.         }
  3150.         if (jarl[whichcounter].face == FACEUP)
  3151.         {   sprintf
  3152.             (   line[LEFTSIDE][2], "%ld (%ld/%ld)",
  3153.                 jarl[whichcounter].strength,
  3154.                 getstrength(JARL, whichcounter, FALSE),
  3155.                 getstrength(JARL, whichcounter, TRUE)
  3156.             );
  3157.         } else
  3158.         {   assert(jarl[whichcounter].face == FACEDOWN);
  3159.             strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
  3160.         }
  3161.         if (jarl[whichcounter].face == FACEUP)
  3162.         {   sprintf
  3163.             (   line[LEFTSIDE][3], "%ld (%ld)",
  3164.                 jarl[whichcounter].moves,
  3165.                 getusualmoves(JARL, whichcounter)
  3166.             );
  3167.         } else
  3168.         {   assert(jarl[whichcounter].face == FACEDOWN);
  3169.             strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN, "Unknown"));
  3170.         }
  3171.         sprintf(line[LEFTSIDE][4], "%ld", jarl[whichcounter].wealth);
  3172.         print_location(jarl[whichcounter].where, 5);
  3173.         sprintf
  3174.         (   line[LEFTSIDE][6], "%s (%ld)",
  3175.             world[jarl[whichcounter].homewhere].name,
  3176.             world[jarl[whichcounter].homewhere].tax
  3177.         );
  3178.         ok = FALSE;
  3179.         for (whichsord = 0; whichsord <= SORDS; whichsord++)
  3180.         {   if
  3181.             (   sord[whichsord].possessortype == JARL
  3182.              && sord[whichsord].possessor == whichcounter
  3183.             )
  3184.             {   ok = TRUE;
  3185.                 counterrow = TRUE;
  3186.                 strcpy(line[LEFTSIDE][7], sord[whichsord].name);
  3187.                 break; // for speed
  3188.         }   }
  3189.         if (!ok)
  3190.         {   strcpy(line[LEFTSIDE][7], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3191.         }
  3192.         print_paralyzed(jarl[whichcounter].loseturn, 8);
  3193.         print_hagall(jarl[whichcounter].hagall, 9);
  3194.         print_sea(jarl[whichcounter].sea, 10);
  3195.         print_routed(jarl[whichcounter].routed, 11);
  3196.         leftlines = 12; // counting from 1
  3197.  
  3198.         strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_MAGIC_TREASURES, "Magic Treasures"));
  3199.         strcat(line[RIGHTSIDE][0], ":");
  3200.         whichline = oldwhichline = 1; // whichline always points to the NEXT line.
  3201.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  3202.         {   if (treasure[whichtreasure].possessortype == JARL
  3203.              && treasure[whichtreasure].possessor     == whichcounter
  3204.             )
  3205.             {   counterrow = TRUE;
  3206.                 strcpy(line[RIGHTSIDE][whichline], " ");
  3207.                 strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
  3208.                 if (whichtreasure == FREYFAXI)
  3209.                 {   strcat(line[RIGHTSIDE][whichline], " (");
  3210.                     stcl_d(numberstring, faxirides);
  3211.                     strcat(line[RIGHTSIDE][whichline], numberstring);
  3212.                     strcat(line[RIGHTSIDE][whichline], " ");
  3213.                     strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_RIDES2, "rides"));
  3214.                     strcat(line[RIGHTSIDE][whichline], ")");
  3215.                 }
  3216.                 whichline++;
  3217.         }   }
  3218.         if (whichline == oldwhichline)
  3219.         {   strcpy(line[RIGHTSIDE][whichline], " ");
  3220.             strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3221.             whichline++;
  3222.         }
  3223.  
  3224.         rightlines = whichline;
  3225.     } elif (countertype == TREASURE)
  3226.     {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_TREASURE_NAME, "Treasure Name"));
  3227.         strcat(line[LEFTSIDE][0], ":");
  3228.         pad(line[LEFTSIDE][0]);
  3229.         strcat(line[LEFTSIDE][0], treasure[whichcounter].name);
  3230.  
  3231.         strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_LOCATION, "Location"));
  3232.         strcat(line[LEFTSIDE][1], ":");
  3233.         pad(line[LEFTSIDE][1]);
  3234.         strcat(line[LEFTSIDE][1], world[treasure[whichcounter].where].name);
  3235.  
  3236.         strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_RIDES, "Rides"));
  3237.         strcat(line[LEFTSIDE][2], ":");
  3238.         pad(line[LEFTSIDE][2]);
  3239.         if (whichcounter == FREYFAXI)
  3240.         {   assert(faxirides != -1);
  3241.             stcl_d(numberstring, faxirides);
  3242.             strcat(line[LEFTSIDE][2], numberstring);
  3243.         } else
  3244.         {   strcat(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_N_A, "n/a"));
  3245.         }
  3246.  
  3247.         line[LEFTSIDE][3][0] = 0; // blank line
  3248.         switch (whichcounter)
  3249.         {
  3250.         case BROSUNGNECKLACE:
  3251.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_1, "This treasure is worth 20 marks. It may"  ));
  3252.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_2, "be traded for any item in a dragon's"     ));
  3253.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_3, "hoard. The wearer moves into the area"    ));
  3254.             strcpy(line[LEFTSIDE][7],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_4, "adjacent to that of the dragon, and gives"));
  3255.             strcpy(line[LEFTSIDE][8],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_5, "it to the dragon while taking what the"   ));
  3256.             strcpy(line[LEFTSIDE][9],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_6, "dragon had. The wearer may then see what" ));
  3257.             strcpy(line[LEFTSIDE][10], GetCatalogStr(li.li_Catalog, MSG_NECKLACE_7, "he had traded for."                       ));
  3258.             leftlines = 11;
  3259.         break;
  3260.         case FREYFAXI:
  3261.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog,     MSG_FAXI_1, "This treasure is a magic horse that can"  ));
  3262.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog,     MSG_FAXI_2, "be ridden only 3 times. It doubles the"   ));
  3263.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog,     MSG_FAXI_3, "rider's movement factor."                 ));
  3264.             leftlines = 7;
  3265.         break;
  3266.         case MAGICSHIRT:
  3267.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog,    MSG_SHIRT_1, "It adds +1 to the combat strength of the" ));
  3268.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog,    MSG_SHIRT_2, "wearer when he is defending. It also adds"));
  3269.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog,    MSG_SHIRT_3, "+1 to the movement factor of the wearer." ));
  3270.             leftlines = 7;
  3271.         break;
  3272.         case MAILCOAT:
  3273.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog,     MSG_COAT_1, "It adds +2 to the combat strength of the" ));
  3274.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog,     MSG_COAT_2, "wearer, but only when the wearer is"      ));
  3275.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog,     MSG_COAT_3, "defending."                               ));
  3276.             leftlines = 7;
  3277.         break;
  3278.         case HEALINGPOTION:
  3279.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog,   MSG_POTION_1, "This treasure can be used only once. It"  ));
  3280.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog,   MSG_POTION_2, "will heal any wounds that the hero is"    ));
  3281.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog,   MSG_POTION_3, "suffering."                               ));
  3282.             leftlines = 7;
  3283.         break;
  3284.         case TELEPORTSCROLL:
  3285.             strcpy(line[LEFTSIDE][4],  GetCatalogStr(li.li_Catalog,   MSG_SCROLL_1, "This treasure can be used only once. It"  ));
  3286.             strcpy(line[LEFTSIDE][5],  GetCatalogStr(li.li_Catalog,   MSG_SCROLL_2, "will teleport the user to any desired"    ));
  3287.             strcpy(line[LEFTSIDE][6],  GetCatalogStr(li.li_Catalog,   MSG_SCROLL_3, "location."                                ));
  3288.             leftlines = 7;
  3289.         break;
  3290.         default:
  3291.             assert(0);
  3292.         break;
  3293.         }
  3294.  
  3295.         rightlines = 0;
  3296.     } elif (countertype == KINGDOM)
  3297.     {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_KINGDOM_NAME, "Kingdom Name"));
  3298.         strcat(line[LEFTSIDE][0], ":");
  3299.         pad(line[LEFTSIDE][0]);
  3300.         strcat(line[LEFTSIDE][0], world[whichcounter].name);
  3301.  
  3302.         strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING, "King"));
  3303.         strcat(line[LEFTSIDE][1], ":");
  3304.         pad(line[LEFTSIDE][1]);
  3305.         if (world[whichcounter].hero == -1)
  3306.         {   strcat(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_KING_NONE, "None"));
  3307.         } else
  3308.         {   strcat(line[LEFTSIDE][1], hero[world[whichcounter].hero].name);
  3309.         }
  3310.  
  3311.         strcpy(line[LEFTSIDE][2], GetCatalogStr(li.li_Catalog, MSG_TAXATION_FACTOR, "Taxation Factor"));
  3312.         strcat(line[LEFTSIDE][2], ":");
  3313.         pad(line[LEFTSIDE][2]);
  3314.         stcl_d(numberstring, world[whichcounter].tax);
  3315.         strcat(line[LEFTSIDE][2], numberstring);
  3316.  
  3317.         strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_TYPE, "Type"));
  3318.         strcat(line[LEFTSIDE][3], ":");
  3319.         pad(line[LEFTSIDE][3]);
  3320.         if (world[whichcounter].type == LAND)
  3321.         {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_LAND, "Land"));
  3322.         } elif (world[whichcounter].type == ISLE)
  3323.         {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_ISLAND, "Island"));
  3324.         } elif (world[whichcounter].type == SEA)
  3325.         {   strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_SEA, "Sea"));
  3326.         } else
  3327.         {   assert(world[whichcounter].type == PENINSULA);
  3328.             strcat(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_PENINSULA, "Peninsula"));
  3329.         }
  3330.  
  3331.         strcpy(line[LEFTSIDE][4], "Is (");
  3332.         strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_ICE, "ice"));
  3333.         strcat(line[LEFTSIDE][4], ")?");
  3334.         pad(line[LEFTSIDE][4]);
  3335.         if (world[whichcounter].is)
  3336.         {   strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_YES, "Yes"));
  3337.         } else
  3338.         {   strcat(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_NO, "No"));
  3339.         }
  3340.  
  3341.         leftlines = 5; // counting from 1
  3342.  
  3343.         strcpy(line[RIGHTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_CONTENTS, "Contents"));
  3344.         strcat(line[RIGHTSIDE][0], ":");
  3345.  
  3346.         whichline = oldwhichline = 1; // whichline always points to the NEXT line.
  3347.         for (whichhero = 0; whichhero <= HEROES; whichhero++)
  3348.         {   if (hero[whichhero].alive && hero[whichhero].where == whichcounter)
  3349.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3350.                 strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_HERO, "Hero"));
  3351.                 strcat(line[RIGHTSIDE][whichline], " ");
  3352.                 strcat(line[RIGHTSIDE][whichline], hero[whichhero].name);
  3353.                 strcat(line[RIGHTSIDE][whichline], " (");
  3354.                 stcl_d(numberstring, hero[whichhero].strength);
  3355.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3356.                 strcat(line[RIGHTSIDE][whichline], "-");
  3357.                 stcl_d(numberstring, hero[whichhero].moves);
  3358.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3359.                 strcat(line[RIGHTSIDE][whichline], ")");
  3360.                 whichline++;
  3361.         }   }
  3362.         for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
  3363.         {   if (jarl[whichjarl].alive && jarl[whichjarl].where == whichcounter)
  3364.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3365.                 if (jarl[whichjarl].face == FACEUP)
  3366.                 {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_JARL, "Jarl"));
  3367.                     strcat(line[RIGHTSIDE][whichline], " ");
  3368.                     strcat(line[RIGHTSIDE][whichline], jarl[whichjarl].name);
  3369.                     strcat(line[RIGHTSIDE][whichline], " (");
  3370.                     stcl_d(numberstring, jarl[whichjarl].strength);
  3371.                     strcat(line[RIGHTSIDE][whichline], numberstring);
  3372.                     strcat(line[RIGHTSIDE][whichline], "-");
  3373.                     stcl_d(numberstring, jarl[whichjarl].moves);
  3374.                     strcat(line[RIGHTSIDE][whichline], numberstring);
  3375.                     strcat(line[RIGHTSIDE][whichline], ")");
  3376.                 } else
  3377.                 {   strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_UNKNOWN_JARL, "Unknown jarl"));
  3378.                     strcat(line[RIGHTSIDE][whichline], " (?-?)");
  3379.                 }
  3380.                 whichline++;
  3381.         }   }
  3382.         for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
  3383.         {   if (monster[whichmonster].alive && monster[whichmonster].where == whichcounter)
  3384.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3385.                 strcat(line[RIGHTSIDE][whichline], monstertypes[monster[whichmonster].species]);
  3386.                 strcat(line[RIGHTSIDE][whichline], " ");
  3387.                 strcat(line[RIGHTSIDE][whichline], monster[whichmonster].name);
  3388.                 strcat(line[RIGHTSIDE][whichline], " (");
  3389.                 stcl_d(numberstring, monster[whichmonster].strength);
  3390.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3391.                 strcat(line[RIGHTSIDE][whichline], "-");
  3392.                 stcl_d(numberstring, monster[whichmonster].moves);
  3393.                 strcat(line[RIGHTSIDE][whichline], numberstring);
  3394.                 strcat(line[RIGHTSIDE][whichline], ")");
  3395.                 whichline++;
  3396.         }   }
  3397.         for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
  3398.         {   if
  3399.             (   treasure[whichtreasure].possessortype == KINGDOM
  3400.              && treasure[whichtreasure].where == whichcounter
  3401.             )
  3402.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3403.                 strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_THE, "The"));
  3404.                 strcat(line[RIGHTSIDE][whichline], " ");
  3405.                 strcat(line[RIGHTSIDE][whichline], treasure[whichtreasure].name);
  3406.                 whichline++;
  3407.         }   }
  3408.         for (whichsord = 0; whichsord <= SORDS; whichsord++)
  3409.         {   if
  3410.             (   sord[whichsord].possessortype == KINGDOM
  3411.              && sord[whichsord].where == whichcounter
  3412.             )
  3413.             {   strcpy(line[RIGHTSIDE][whichline], " ");
  3414.                 strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_SWORD, "Sword"));
  3415.                 strcat(line[RIGHTSIDE][whichline], " ");
  3416.                 strcat(line[RIGHTSIDE][whichline], sord[whichsord].name);
  3417.                 whichline++;
  3418.         }   }
  3419.  
  3420.         if (whichline == oldwhichline)
  3421.         {   strcpy(line[RIGHTSIDE][whichline], " ");
  3422.             strcat(line[RIGHTSIDE][whichline], GetCatalogStr(li.li_Catalog, MSG_NONE, "None"));
  3423.             whichline++;
  3424.         }
  3425.  
  3426.         rightlines = whichline;
  3427.     } elif (countertype == SORD)
  3428.     {   strcpy(line[LEFTSIDE][0], GetCatalogStr(li.li_Catalog, MSG_SWORD_NAME, "Sword Name"));
  3429.         strcat(line[LEFTSIDE][0], ":");
  3430.         pad(line[LEFTSIDE][0]);
  3431.         strcat(line[LEFTSIDE][0], sord[whichcounter].name);
  3432.  
  3433.         strcpy(line[LEFTSIDE][1], GetCatalogStr(li.li_Catalog, MSG_LOCATION, "Location"));
  3434.         strcat(line[LEFTSIDE][1], ":");
  3435.         pad(line[LEFTSIDE][1]);
  3436.         strcat(line[LEFTSIDE][1], world[sord[whichcounter].where].name);
  3437.  
  3438.         line[LEFTSIDE][2][0] = 0; // blank line
  3439.         switch(whichcounter)
  3440.         {
  3441.         case BALMUNG:
  3442.             strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog,  MSG_BALMUNG_1, "In any fight where its wielder is"        ));
  3443.             strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog,  MSG_BALMUNG_2, "attacking an enemy wearing magic armour," ));
  3444.             strcpy(line[LEFTSIDE][5], GetCatalogStr(li.li_Catalog,  MSG_BALMUNG_3, "it cancels out the benefit of the magic"  ));
  3445.             strcpy(line[LEFTSIDE][6], GetCatalogStr(li.li_Catalog,  MSG_BALMUNG_4, "armour. Thus, the Mail Coat and the Magic"));
  3446.             strcpy(line[LEFTSIDE][7], GetCatalogStr(li.li_Catalog,  MSG_BALMUNG_5, "Shirt provide no protection against it."  ));
  3447.             leftlines = 8;
  3448.         break;
  3449.         case HRUNTING:
  3450.             strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_1, "The other side must flee instead when the"));
  3451.             strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_2, "combat result would be that the wielder's"));
  3452.             strcpy(line[LEFTSIDE][5], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_3, "side must flee."                          ));
  3453.             leftlines = 6;
  3454.         break;
  3455.         case LOVI:
  3456.             strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog,     MSG_LOVI_1, "In any battle against a side including"   ));
  3457.             strcpy(line[LEFTSIDE][4], GetCatalogStr(li.li_Catalog,     MSG_LOVI_2, "jarls, it adds an additional +2 to the"   ));
  3458.             strcpy(line[LEFTSIDE][5], GetCatalogStr(li.li_Catalog,     MSG_LOVI_3, "wielder's combat factor."                 ));
  3459.             leftlines = 6;
  3460.         break;
  3461.         default:
  3462.             strcpy(line[LEFTSIDE][3], GetCatalogStr(li.li_Catalog, MSG_NO_SPECIAL_POWERS, "No special powers."));
  3463.             leftlines = 4;
  3464.         break;
  3465.         }
  3466.  
  3467.         rightlines = 0;
  3468.     }
  3469.  
  3470.     if (leftlines >= rightlines)
  3471.     {   lines = leftlines;
  3472.     } else
  3473.     {   lines = rightlines;
  3474.     }
  3475.     if (rightlines > 0)
  3476.     {   wide = 1;
  3477.     } else
  3478.     {   wide = 0;
  3479.     }
  3480.  
  3481.     if (!(InfoWindowPtr = (struct Window *) OpenWindowTags(NULL,
  3482.         WA_Left,          (SCREENXPIXEL / 2) - ((360 + (280 * wide )) / 2),
  3483.         WA_Top,           (SCREENYPIXEL / 2) - (( 30 + ( 10 * lines)) / 2),
  3484.         WA_Width,         360 + (280 * wide ),
  3485.         WA_Height,         30 + ( 10 * lines),
  3486.         WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  3487.         WA_Title,         GetCatalogStr(li.li_Catalog, MSG_INFORMATION, "Information"),
  3488.         WA_Gadgets,       NULL,
  3489.         WA_CustomScreen,  ScreenPtr,
  3490.         WA_DragBar,       TRUE,
  3491.         WA_CloseGadget,   TRUE,
  3492.         WA_NoCareRefresh, TRUE,
  3493.         WA_Activate,      TRUE,
  3494.         WA_GimmeZeroZero, TRUE,
  3495.     TAG_DONE)))
  3496.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open information window!\0", 24);
  3497.         cleanexit(EXIT_FAILURE);
  3498.     }
  3499.     fillwindow(InfoWindowPtr);
  3500.     SetDrMd(InfoWindowPtr->RPort, JAM1);
  3501.  
  3502.     if (countertype == HERO || countertype == JARL || countertype == MONSTER)
  3503.     {   for (whichline = 0; whichline < leftlines; whichline++)
  3504.         {   SetAPen(InfoWindowPtr->RPort, BLACK);
  3505.             Move(InfoWindowPtr->RPort, 12 + 1,            13 + (whichline * 10) + 1);
  3506.             Text(InfoWindowPtr->RPort, label[whichline], strlen(label[whichline]));
  3507.             Move(InfoWindowPtr->RPort, 12 + (22 * 8) + 1, 13 + (whichline * 10) + 1);
  3508.             Text(InfoWindowPtr->RPort, line[LEFTSIDE][whichline], strlen(line[LEFTSIDE][whichline]));
  3509.             SetAPen(InfoWindowPtr->RPort, WHITE);
  3510.             Move(InfoWindowPtr->RPort, 12,                13 + (whichline * 10));
  3511.             Text(InfoWindowPtr->RPort, label[whichline], strlen(label[whichline]));
  3512.             Move(InfoWindowPtr->RPort, 12 + (22 * 8),     13 + (whichline * 10));
  3513.             Text(InfoWindowPtr->RPort, line[LEFTSIDE][whichline], strlen(line[LEFTSIDE][whichline]));
  3514.     }   }
  3515.     else
  3516.     {   for (whichline = 0; whichline < leftlines; whichline++)
  3517.         {   SetAPen(InfoWindowPtr->RPort, BLACK);
  3518.             Move(InfoWindowPtr->RPort, 12 + 1,        13 + (whichline * 10) + 1);
  3519.             Text(InfoWindowPtr->RPort, line[LEFTSIDE][whichline], strlen(line[LEFTSIDE][whichline]));
  3520.             SetAPen(InfoWindowPtr->RPort, WHITE);
  3521.             Move(InfoWindowPtr->RPort, 12,            13 + (whichline * 10));
  3522.             Text(InfoWindowPtr->RPort, line[LEFTSIDE][whichline], strlen(line[LEFTSIDE][whichline]));
  3523.     }   }
  3524.  
  3525.     if (wide)
  3526.     {   for (whichline = 0; whichline < rightlines; whichline++)
  3527.         {   SetAPen(InfoWindowPtr->RPort, BLACK);
  3528.             Move(InfoWindowPtr->RPort, 360 + 12 + 1,  13 + (whichline * 10) + 1);
  3529.             Text(InfoWindowPtr->RPort, line[RIGHTSIDE][whichline], strlen(line[RIGHTSIDE][whichline]));
  3530.             SetAPen(InfoWindowPtr->RPort, WHITE);
  3531.             Move(InfoWindowPtr->RPort, 360 + 12,      13 + (whichline * 10));
  3532.             Text(InfoWindowPtr->RPort, line[RIGHTSIDE][whichline], strlen(line[RIGHTSIDE][whichline]));
  3533.     }   }
  3534.  
  3535.     if (counterrow)
  3536.     {   info(countertype, whichcounter);
  3537.     }
  3538.  
  3539.     infoloop();
  3540. }
  3541.  
  3542. MODULE void flash(SLONG country)
  3543. {   SLONG colour;
  3544.  
  3545.     if (country < 0 || country > 65)
  3546.     {   return;
  3547.     }
  3548.  
  3549.     if (country == 9)
  3550.     {   colour = 89; // Suder Gotland
  3551.     } elif (country == 10)
  3552.     {   colour = 90; // Juteland
  3553.     } elif (country == 11)
  3554.     {   colour = 91; // Scandia
  3555.     } else
  3556.     {   colour = country + 8;
  3557.     }
  3558.  
  3559.     SetRGB4(&ScreenPtr->ViewPort, colour, 15, 15, 15); // white flash
  3560.     Delay(2); // hold the flash
  3561.  
  3562.     if (country >= 36)
  3563.     {   SetRGB4(&ScreenPtr->ViewPort, colour,  0,  0,  9); // dark blue
  3564.     } elif (world[country].hero != -1)
  3565.     {   SetRGB4
  3566.         (   &ScreenPtr->ViewPort,
  3567.             colour,
  3568.             herocolour[world[country].hero].red,
  3569.             herocolour[world[country].hero].green,
  3570.             herocolour[world[country].hero].blue
  3571.         );
  3572.     } elif (world[country].is)
  3573.     {   SetRGB4(&ScreenPtr->ViewPort, colour, 12, 12, 12); // light grey ice
  3574.     } else
  3575.     {   SetRGB4
  3576.         (   &ScreenPtr->ViewPort,
  3577.             colour,
  3578.             taxcolours[world[country].tax].red,
  3579.             taxcolours[world[country].tax].green,
  3580.             taxcolours[world[country].tax].blue
  3581.         );
  3582. }   }
  3583.  
  3584. MODULE void summarywindow(void)
  3585. {   SLONG                count,
  3586.                          i, j,
  3587.                          length,
  3588.                          linecolour[HEROES + 1],
  3589.                          lines = 0;
  3590.     FLAG                 nomore = FALSE,
  3591.                          ok;
  3592.  
  3593.     strcpy(line[0][0], GetCatalogStr(li.li_Catalog, MSG_SUMMARYLINE, "Hero Name  C-M J K S T C S R Glry Luck $$$$"));
  3594.  
  3595.                      /* Hero Name  C-M J K S T C S R Glry Luck $$$$
  3596.                                    o o a i w r o t u
  3597.                                    m v r n o e n a n
  3598.                                    b e l g r a t t e
  3599.                                    a m s d d s r u
  3600.                                    t e   o   u o s
  3601.                                      n   m   r l
  3602.                                      t   s   e
  3603.                                              s
  3604.  
  3605.                         Heldenname K-B J K S S K S @ Ruhm Glck $$$$
  3606.                                    a e a ö c c o t @
  3607.                                    m w r n h h n a @
  3608.                                    p e l i w ä t t @
  3609.                                    f g s g e t r u @
  3610.                                      u   r r z o s @
  3611.                                      n   e t e l
  3612.                                      g   i     l
  3613.                                      s   c     e
  3614.                                          h
  3615.                                          e */
  3616.  
  3617.     for (i = 0; i <= HEROES; i++)
  3618.     {   if (hero[i].control != NONE)
  3619.         {   linecolour[lines] = 136 + i;
  3620.  
  3621.             lines++;
  3622.  
  3623.             strcpy(line[0][lines], hero[i].name);
  3624.  
  3625.             length = strlen(hero[i].name);
  3626.             for (j = length; j < 11; j++)
  3627.             {   strcat(line[0][lines], " ");
  3628.             }
  3629.  
  3630.             stcl_d(numberstring, hero[i].strength);
  3631.             strcat(line[0][lines], numberstring);
  3632.             strcat(line[0][lines], "-");
  3633.  
  3634.             stcl_d(numberstring, hero[i].moves);
  3635.             strcat(line[0][lines], numberstring);
  3636.             strcat(line[0][lines], " ");
  3637.  
  3638.             count = 0;
  3639.             for (j = 0; j <= JARLS; j++)
  3640.             {   if (jarl[j].alive && jarl[j].hero == i)
  3641.                 {   count++;
  3642.             }   }
  3643.             stcl_d(numberstring, count);
  3644.             strcat(line[0][lines], numberstring);
  3645.             strcat(line[0][lines], " ");
  3646.  
  3647.             count = 0;
  3648.             for (j = 0; j <= 35; j++)
  3649.             {   if (world[j].hero == i)
  3650.                 {   count++;
  3651.             }   }
  3652.             stcl_d(numberstring, count);
  3653.             strcat(line[0][lines], numberstring);
  3654.             strcat(line[0][lines], " ");
  3655.  
  3656.             ok = FALSE;
  3657.             for (j = 0; j <= SORDS; j++)
  3658.             {   if
  3659.                 (   sord[j].possessortype == HERO
  3660.                  && sord[j].possessor     == i
  3661.                 )
  3662.                 {   numberstring[0] = sord[j].name[0];
  3663.                     numberstring[1] = 0;
  3664.                     strcat(line[0][lines], numberstring);
  3665.                     ok = TRUE;
  3666.                     break;
  3667.             }   }
  3668.             if (!ok)
  3669.             {   strcat(line[0][lines], "-");
  3670.             }
  3671.             strcat(line[0][lines], " ");
  3672.  
  3673.             count = 0;
  3674.             for (j = 0; j <= TREASURES; j++)
  3675.             {   if
  3676.                 (   (   treasure[j].possessortype == HERO
  3677.                      && treasure[j].possessor     == i
  3678.                     )
  3679.                  || (   treasure[j].possessortype == JARL
  3680.                      && jarl[treasure[j].possessor].hero == i
  3681.                 )   )
  3682.                 {   count++;
  3683.             }   }
  3684.             stcl_d(numberstring, count);
  3685.             strcat(line[0][lines], numberstring);
  3686.             strcat(line[0][lines], " ");
  3687.  
  3688.             if (hero[i].control == HUMAN)
  3689.             {   strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_CHAR_HUMAN, "H"));
  3690.             } else
  3691.             {   assert(hero[i].control == AMIGA);
  3692.                 strcat(line[0][lines], "A");
  3693.             }
  3694.             strcat(line[0][lines], " ");
  3695.  
  3696.             if (!hero[i].alive)
  3697.             {   strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_CHAR_DEAD,    "D"));
  3698.             } elif (hero[i].wounded)
  3699.             {   strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_CHAR_WOUNDED, "W"));
  3700.             } else
  3701.             {   strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_CHAR_HEALTHY, "H"));
  3702.             }
  3703.  
  3704.             strcat(line[0][lines], " ");
  3705.             if (hero[i].rune == -1)
  3706.             {   strcat(line[0][lines], "-");
  3707.             } else
  3708.             {   numberstring[0] = rune[hero[i].rune].name[0];
  3709.                 numberstring[1] = 0;
  3710.                 strcat(line[0][lines], numberstring);
  3711.             }
  3712.  
  3713.             stcl_d(numberstring, hero[i].glory);
  3714.             length = strlen(numberstring);
  3715.             for (j = length; j < 5; j++)
  3716.             {   strcat(line[0][lines], " ");
  3717.             }
  3718.             strcat(line[0][lines], numberstring);
  3719.  
  3720.             stcl_d(numberstring, hero[i].luck);
  3721.             length = strlen(numberstring);
  3722.             for (j = length; j < 5; j++)
  3723.             {   strcat(line[0][lines], " ");
  3724.             }
  3725.             strcat(line[0][lines], numberstring);
  3726.  
  3727.             count = hero[i].wealth;
  3728.             for (j = 0; j <= JARLS; j++)
  3729.             {   if (jarl[j].alive && jarl[j].hero == i)
  3730.                 {   count += jarl[j].wealth;
  3731.             }   }
  3732.             stcl_d(numberstring, count);
  3733.             length = strlen(numberstring);
  3734.             for (j = length; j < 5; j++)
  3735.             {   strcat(line[0][lines], " ");
  3736.             }
  3737.             strcat(line[0][lines], numberstring);
  3738.     }   }
  3739.  
  3740.     line[0][++lines][0] = 0;
  3741.  
  3742.     count = 0;
  3743.     for (i = 0; i <= MONSTERS; i++)
  3744.     {   if (!monster[i].taken)
  3745.         {   count++;
  3746.     }   }
  3747.     sprintf
  3748.     (   line[0][++lines], "%s:",
  3749.         GetCatalogStr(li.li_Catalog, MSG_MONSTERS_IN_PILE, "Monsters in Pile")
  3750.     );
  3751.     pad(line[0][lines]);
  3752.     stcl_d(numberstring, count);
  3753.     strcat(line[0][lines], numberstring);
  3754.     strcat(line[0][lines], " ");
  3755.     strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
  3756.     strcat(line[0][lines], " ");
  3757.     stcl_d(numberstring, MONSTERS + 1);
  3758.     strcat(line[0][lines], numberstring);
  3759.  
  3760.     count = 0;
  3761.     for (i = 0; i <= JARLS; i++)
  3762.     {   if (!jarl[i].taken)
  3763.         {   count++;
  3764.     }   }
  3765.     sprintf
  3766.     (   line[0][++lines], "%s:",
  3767.         GetCatalogStr(li.li_Catalog, MSG_JARLS_IN_PILE, "Jarls in Pile")
  3768.     );
  3769.     pad(line[0][lines]);
  3770.     stcl_d(numberstring, count);
  3771.     strcat(line[0][lines], numberstring);
  3772.     strcat(line[0][lines], " ");
  3773.     strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
  3774.     strcat(line[0][lines], " ");
  3775.     stcl_d(numberstring, JARLS + 1);
  3776.     strcat(line[0][lines], numberstring);
  3777.  
  3778.     count = 0;
  3779.     for (i = 0; i <= TREASURES; i++)
  3780.     {   if (!treasure[i].taken)
  3781.         {   count++;
  3782.     }   }
  3783.     sprintf
  3784.     (   line[0][++lines], "%s:",
  3785.         GetCatalogStr(li.li_Catalog, MSG_TREASURES_IN_PILE, "Treasures in Pile")
  3786.     );
  3787.     pad(line[0][lines]);
  3788.     stcl_d(numberstring, count);
  3789.     strcat(line[0][lines], numberstring);
  3790.     strcat(line[0][lines], " ");
  3791.     strcat(line[0][lines], GetCatalogStr(li.li_Catalog, MSG_OF, "of"));
  3792.     strcat(line[0][lines], " ");
  3793.     stcl_d(numberstring, TREASURES + 1);
  3794.     strcat(line[0][lines], numberstring);
  3795.  
  3796.     if (!(InfoWindowPtr = (struct Window *) OpenWindowTags(NULL,
  3797.         WA_Left,          (SCREENXPIXEL / 2) - (SUMMARYWIDTH / 2),
  3798.         WA_Top,           (SCREENYPIXEL / 2) - ((SUMMARYHEIGHT + (lines * 10)) / 2),
  3799.         WA_Width,         SUMMARYWIDTH,
  3800.         WA_Height,        SUMMARYHEIGHT + (lines * 10),
  3801.         WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  3802.         WA_Title,         GetCatalogStr(li.li_Catalog, MSG_GAME_SUMMARY, "Game Summary"),
  3803.         WA_Gadgets,       NULL,
  3804.         WA_CustomScreen,  ScreenPtr,
  3805.         WA_DragBar,       TRUE,
  3806.         WA_CloseGadget,   TRUE,
  3807.         WA_NoCareRefresh, TRUE,
  3808.         WA_Activate,      TRUE,
  3809.         WA_GimmeZeroZero, TRUE,
  3810.     TAG_DONE)))
  3811.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open summary window!\0", 24);
  3812.         cleanexit(EXIT_FAILURE);
  3813.     }
  3814.  
  3815.     fillwindow(InfoWindowPtr);
  3816.     SetDrMd(InfoWindowPtr->RPort, JAM1);
  3817.  
  3818.     SetAPen(InfoWindowPtr->RPort, BLACK);
  3819.     Move(InfoWindowPtr->RPort, 12 + 1,            13 + 1);
  3820.     Text(InfoWindowPtr->RPort, line[0][0], strlen(line[0][0])); // headings
  3821.     Move(InfoWindowPtr->RPort, 12 + 1,            16 + 1);
  3822.     Draw(InfoWindowPtr->RPort, SUMMARYWIDTH - 20, 16 + 1); // underline
  3823.     SetAPen(InfoWindowPtr->RPort, WHITE);
  3824.     Move(InfoWindowPtr->RPort, 12,                13);
  3825.     Text(InfoWindowPtr->RPort, line[0][0], strlen(line[0][0])); // headings
  3826.     Move(InfoWindowPtr->RPort, 12,                16);
  3827.     Draw(InfoWindowPtr->RPort, SUMMARYWIDTH - 20, 16); // underline
  3828.     for (i = 1; i <= lines; i++)
  3829.     {   SetAPen(InfoWindowPtr->RPort, BLACK);
  3830.         Move(InfoWindowPtr->RPort, 12 + 1,        15 + (i * 10) + 1);
  3831.         Text(InfoWindowPtr->RPort, line[0][i], strlen(line[0][i]));
  3832.         if (DisplayDepth >= DEPTH && !nomore)
  3833.         {   SetAPen(InfoWindowPtr->RPort, linecolour[i - 1]);
  3834.         } else
  3835.         {   SetAPen(InfoWindowPtr->RPort, WHITE);
  3836.         }
  3837.         Move(InfoWindowPtr->RPort, 12,            15 + (i * 10));
  3838.         Text(InfoWindowPtr->RPort, line[0][i], strlen(line[0][i]));
  3839.         if (line[0][i][0] == 0)
  3840.         {   nomore = TRUE;
  3841.     }   }
  3842.  
  3843.     infoloop();
  3844. }
  3845.  
  3846. EXPORT void screenoff(void)
  3847. {   if (dbuf)
  3848.     {   if (!(ScreenBuf[1] = AllocScreenBuffer(ScreenPtr, NULL, SB_COPY_BITMAP)))
  3849.         {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't allocate alternate screen buffer!\0", 24);
  3850.             cleanexit(EXIT_FAILURE);
  3851.         }
  3852.  
  3853.         WaitTOF();
  3854.  
  3855.         while (!(ChangeScreenBuffer(ScreenPtr, ScreenBuf[1])));
  3856. }   }
  3857.  
  3858. EXPORT void screenon(void)
  3859. {   WaitTOF();
  3860.  
  3861.     if (dbuf)
  3862.     {   while (!(ChangeScreenBuffer(ScreenPtr, ScreenBuf[0])));
  3863.  
  3864.         FreeScreenBuffer(ScreenPtr, ScreenBuf[1]);
  3865.         ScreenBuf[1] = NULL;
  3866. }   }
  3867.  
  3868. EXPORT void hint(STRPTR thehint1, STRPTR thehint2)
  3869. {   TEXT thehint[19 + 1];
  3870.  
  3871.     strcpy(thehint, thehint1);
  3872.     strcat(thehint, "/");
  3873.     strcat(thehint, thehint2);
  3874.  
  3875.     SetAPen(MainWindowPtr->RPort, WHITE);
  3876.     Move(MainWindowPtr->RPort, 640 - 4 - ((10 + strlen(thehint1)) * 8), MESSAGEY + 26);
  3877.     Text(MainWindowPtr->RPort, thehint, strlen(thehint));
  3878. }
  3879.  
  3880. MODULE void cycle(SLONG whichhero, UWORD qual)
  3881. {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  3882.     {   if (hero[whichhero].control == 0)
  3883.         {   hero[whichhero].control = 2;
  3884.         } else
  3885.         {   hero[whichhero].control--;
  3886.     }   }
  3887.     else
  3888.     {   if (hero[whichhero].control == 2)
  3889.         {   hero[whichhero].control = 0;
  3890.         } else
  3891.         {   hero[whichhero].control++;
  3892.     }   }
  3893.     GT_SetGadgetAttrs(CycleGadgetPtr[whichhero], MainWindowPtr, NULL, GTCY_Active, hero[whichhero].control, TAG_DONE);
  3894. }
  3895.  
  3896. MODULE void docwindow(SLONG number)
  3897. {   SLONG                lines = 0, // to avoid spurious compiler warnings
  3898.                          whichline;
  3899.     SWORD                width, height;
  3900.  
  3901.     switch (number)
  3902.     {
  3903.     case 1:
  3904.         // runes
  3905.         strcpy(line[0][0],  rune[AMSIR].name);
  3906.         strcat(line[0][0],  ", ");
  3907.         strcat(line[0][0],  rune[AMSIR].desc);
  3908.         strcpy(line[0][1],  GetCatalogStr(li.li_Catalog, MSG_AMSIR_1, "A hero with this rune has twice the"      ));
  3909.         strcpy(line[0][2],  GetCatalogStr(li.li_Catalog, MSG_AMSIR_2, "chance of having the gods notice him."    ));
  3910.                line[0][3][0] = 0;
  3911.         strcpy(line[0][4],  rune[EON].name);
  3912.         strcat(line[0][4],  ", ");
  3913.         strcat(line[0][4],  rune[EON].desc);
  3914.         strcpy(line[0][5],  GetCatalogStr(li.li_Catalog, MSG_EON_1,   "+1 to movement factor."                   ));
  3915.                line[0][6][0] = 0;
  3916.         strcpy(line[0][7],  rune[GEOFU].name);
  3917.         strcat(line[0][7],  ", ");
  3918.         strcat(line[0][7],  rune[GEOFU].desc);
  3919.         strcpy(line[0][8],  GetCatalogStr(li.li_Catalog, MSG_GEOFU_1, "A hero with this rune will have all the"  ));
  3920.         strcpy(line[0][9],  GetCatalogStr(li.li_Catalog, MSG_GEOFU_2, "areas in his kingdom yield one additional"));
  3921.         strcpy(line[0][10], GetCatalogStr(li.li_Catalog, MSG_GEOFU_3, "mark over and above the tax factor each"  ));
  3922.         strcpy(line[0][11], GetCatalogStr(li.li_Catalog, MSG_GEOFU_4, "turn."                                    ));
  3923.                line[0][12][0] = 0;
  3924.         strcpy(line[0][13], rune[ING].name);
  3925.         strcat(line[0][13], ", ");
  3926.         strcat(line[0][13], rune[ING].desc);
  3927.         strcpy(line[0][14], GetCatalogStr(li.li_Catalog, MSG_ING_1,   "A hero with this rune can heal his wounds"));
  3928.         strcpy(line[0][15], GetCatalogStr(li.li_Catalog, MSG_ING_2,   "by spending one turn anywhere at rest."   ));
  3929.                line[0][16][0] = 0;
  3930.         strcpy(line[0][17], rune[OGAL].name);
  3931.         strcat(line[0][17], ", ");
  3932.         strcat(line[0][17], rune[OGAL].desc);
  3933.         strcpy(line[0][18], GetCatalogStr(li.li_Catalog, MSG_OGAL_1,  "+1 to combat strength."                   ));
  3934.                line[0][19][0] = 0;
  3935.         strcpy(line[0][20], rune[SYGIL].name);
  3936.         strcat(line[0][20], ", ");
  3937.         strcat(line[0][20], rune[SYGIL].desc);
  3938.         strcpy(line[0][21], GetCatalogStr(li.li_Catalog, MSG_SYGIL_1, "Every time a spell is cast at the hero"   ));
  3939.         strcpy(line[0][22], GetCatalogStr(li.li_Catalog, MSG_SYGIL_2, "who has this rune, it may not affect the" ));
  3940.         strcpy(line[0][23], GetCatalogStr(li.li_Catalog, MSG_SYGIL_3, "hero (though it may affect those in the"  ));
  3941.         strcpy(line[0][24], GetCatalogStr(li.li_Catalog, MSG_SYGIL_4, "same area with him)."                     ));
  3942.         lines = 25; // counting from 1
  3943.     break;
  3944.     case 2:
  3945.         // spells
  3946.         strcpy(line[0][0],  "Hagall (");
  3947.         strcat(line[0][0],  GetCatalogStr(li.li_Catalog, MSG_HAIL,           "hail"                                ));
  3948.         strcat(line[0][0],  ")");
  3949.         strcpy(line[0][1],  GetCatalogStr(li.li_Catalog, MSG_HAGALL_1,       "Reduces the combat factor of each counter"));
  3950.         strcpy(line[0][2],  GetCatalogStr(li.li_Catalog, MSG_HAGALL_2,       "in the area (including the caster) by one"));
  3951.         strcpy(line[0][3],  GetCatalogStr(li.li_Catalog, MSG_HAGALL_3,       "for the rest of the turn. It also"        ));
  3952.         strcpy(line[0][4],  GetCatalogStr(li.li_Catalog, MSG_HAGALL_4,       "prevents any of the counters from moving" ));
  3953.         strcpy(line[0][5],  GetCatalogStr(li.li_Catalog, MSG_HAGALL_5,       "by sea next turn."                        ));
  3954.                line[0][6][0] = 0;
  3955.         strcpy(line[0][7],  "Is (");
  3956.         strcat(line[0][7],  GetCatalogStr(li.li_Catalog, MSG_ICE,            "ice"                                      ));
  3957.         strcat(line[0][7],  ")");
  3958.         strcpy(line[0][8],  GetCatalogStr(li.li_Catalog, MSG_IS_1,           "Makes it impossible for any hero to"      ));
  3959.         strcpy(line[0][9],  GetCatalogStr(li.li_Catalog, MSG_IS_2,           "found, or continue to have a kingdom in"  ));
  3960.         strcpy(line[0][10], GetCatalogStr(li.li_Catalog, MSG_IS_3,           "that country."                            ));
  3961.                line[0][11][0] = 0;
  3962.         strcpy(line[0][12], "Jara (");
  3963.         strcat(line[0][12], GetCatalogStr(li.li_Catalog, MSG_LOSE_NEXT_TURN, "lose next turn"                           ));
  3964.         strcat(line[0][12], ")");
  3965.         strcpy(line[0][13], GetCatalogStr(li.li_Catalog, MSG_JARA_1,         "All in the area lose their next turn."    ));
  3966.                line[0][14][0] = 0;
  3967.         if (!(li.li_Catalog)) // only if running in English
  3968.         {   strcpy(line[0][15], "Nied (");
  3969.             strcat(line[0][15], GetCatalogStr(li.li_Catalog, MSG_N_R_A_L_N_T,    "no result and lose next turn"             ));
  3970.             strcat(line[0][15], ")");
  3971.         } else // German rune description text is too long
  3972.         {   strcpy(line[0][15], "Nied");
  3973.         }
  3974.         strcpy(line[0][16], GetCatalogStr(li.li_Catalog, MSG_NIED_1,         "Makes the combat result an automatic \"no"));
  3975.         strcpy(line[0][17], GetCatalogStr(li.li_Catalog, MSG_NIED_2,         "result\" and causes all in the area to"   ));
  3976.         strcpy(line[0][18], GetCatalogStr(li.li_Catalog, MSG_NIED_3,         "lose one turn."                           ));
  3977.                line[0][19][0] = 0;
  3978.         strcpy(line[0][20], "Wynn (");
  3979.         strcat(line[0][20], GetCatalogStr(li.li_Catalog, MSG_FLEEING,        "fleeing"                                  ));
  3980.         strcat(line[0][20], ")");
  3981.         strcpy(line[0][21], GetCatalogStr(li.li_Catalog, MSG_WYNN_1,         "Forces all of the heroes and jarls in the"));
  3982.         strcpy(line[0][22], GetCatalogStr(li.li_Catalog, MSG_WYNN_2,         "area to flee."                            ));
  3983.                line[0][23][0] = 0;
  3984.         strcpy(line[0][24], "Yr (");
  3985.         strcat(line[0][24], GetCatalogStr(li.li_Catalog, MSG_WOUNDING,       "wounding"                                 ));
  3986.         strcat(line[0][24], ")");
  3987.         strcpy(line[0][25], GetCatalogStr(li.li_Catalog, MSG_YR_1,           "Causes all counters in the area (except"  ));
  3988.         strcpy(line[0][26], GetCatalogStr(li.li_Catalog, MSG_YR_2,           "face down jarls or monster counters) to"  ));
  3989.         strcpy(line[0][27], GetCatalogStr(li.li_Catalog, MSG_YR_3,           "be wounded."                              ));
  3990.         lines = 28; // counting from 1
  3991.     break;
  3992.     case 3:
  3993.         // swords
  3994.         strcpy(line[0][0],  sord[BALMUNG].name);
  3995.         strcpy(line[0][1],  GetCatalogStr(li.li_Catalog, MSG_BALMUNG_1,         "In any fight where its wielder is"        ));
  3996.         strcpy(line[0][2],  GetCatalogStr(li.li_Catalog, MSG_BALMUNG_2,         "attacking an enemy wearing magic armour," ));
  3997.         strcpy(line[0][3],  GetCatalogStr(li.li_Catalog, MSG_BALMUNG_3,         "it cancels out the benefit of the magic"  ));
  3998.         strcpy(line[0][4],  GetCatalogStr(li.li_Catalog, MSG_BALMUNG_4,         "armour. Thus, the Mail Coat and the Magic"));
  3999.         strcpy(line[0][5],  GetCatalogStr(li.li_Catalog, MSG_BALMUNG_5,         "Shirt provide no protection against it."  ));
  4000.                line[0][6][0] = 0;
  4001.         strcpy(line[0][7],  sord[DRAGVENDILL].name);
  4002.         strcpy(line[0][8],  GetCatalogStr(li.li_Catalog, MSG_NO_SPECIAL_POWERS, "No special powers."                       ));
  4003.                line[0][9][0] = 0;
  4004.         strcpy(line[0][10], sord[GRAM].name);
  4005.         strcpy(line[0][11], GetCatalogStr(li.li_Catalog, MSG_NO_SPECIAL_POWERS, "No special powers."                       ));
  4006.                line[0][12][0] = 0;
  4007.         strcpy(line[0][13], sord[HRUNTING].name);
  4008.         strcpy(line[0][14], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_1,        "The other side must flee instead when the"));
  4009.         strcpy(line[0][15], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_2,        "combat result would be that the wielder's"));
  4010.         strcpy(line[0][16], GetCatalogStr(li.li_Catalog, MSG_HRUNTING_3,        "side must flee."                          ));
  4011.                line[0][17][0] = 0;
  4012.         strcpy(line[0][18], sord[LOVI].name);
  4013.         strcpy(line[0][19], GetCatalogStr(li.li_Catalog, MSG_LOVI_1,            "In any battle against a side including"   ));
  4014.         strcpy(line[0][20], GetCatalogStr(li.li_Catalog, MSG_LOVI_2,            "jarls, it adds an additional +2 to the"   ));
  4015.         strcpy(line[0][21], GetCatalogStr(li.li_Catalog, MSG_LOVI_3,            "wielder's combat factor."                 ));
  4016.                line[0][22][0] = 0;
  4017.         strcpy(line[0][23], sord[TYRFING].name);
  4018.         strcpy(line[0][24], GetCatalogStr(li.li_Catalog, MSG_NO_SPECIAL_POWERS, "No special powers."                       ));
  4019.         lines = 25; // counting from 1
  4020.     break;
  4021.     case 4:
  4022.         // treasures
  4023.         strcpy(line[0][0],  GetCatalogStr(li.li_Catalog, MSG_BROSUNG_NECKLACE, "Brosung Necklace"                         ));
  4024.         strcpy(line[0][1],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_1,       "This treasure is worth 20 marks. It may"  ));
  4025.         strcpy(line[0][2],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_2,       "be traded for any item in a dragon's"     ));
  4026.         strcpy(line[0][3],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_3,       "hoard. The wearer moves into the area"    ));
  4027.         strcpy(line[0][4],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_4,       "adjacent to that of the dragon, and gives"));
  4028.         strcpy(line[0][5],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_5,       "it to the dragon while taking what the"   ));
  4029.         strcpy(line[0][6],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_6,       "dragon had. The wearer may then see what" ));
  4030.         strcpy(line[0][7],  GetCatalogStr(li.li_Catalog, MSG_NECKLACE_7,       "he had traded for."                       ));
  4031.                line[0][8][0] = 0;
  4032.         strcpy(line[0][9],                                                     "Frey Faxi"                                 );
  4033.         strcpy(line[0][10], GetCatalogStr(li.li_Catalog, MSG_FAXI_1,           "This treasure is a magic horse that can"  ));
  4034.         strcpy(line[0][11], GetCatalogStr(li.li_Catalog, MSG_FAXI_2,           "be ridden only 3 times. It doubles the"   ));
  4035.         strcpy(line[0][12], GetCatalogStr(li.li_Catalog, MSG_FAXI_3,           "rider's movement factor."                 ));
  4036.                line[0][13][0] = 0;
  4037.         strcpy(line[0][14], GetCatalogStr(li.li_Catalog, MSG_MAGIC_SHIRT,      "Magic Shirt"                              ));
  4038.         strcpy(line[0][15], GetCatalogStr(li.li_Catalog, MSG_SHIRT_1,          "It adds +1 to the combat strength of the" ));
  4039.         strcpy(line[0][16], GetCatalogStr(li.li_Catalog, MSG_SHIRT_2,          "wearer when he is defending. It also adds"));
  4040.         strcpy(line[0][17], GetCatalogStr(li.li_Catalog, MSG_SHIRT_3,          "+1 to the movement factor of the wearer." ));
  4041.                line[0][18][0] = 0;
  4042.         strcpy(line[0][19], GetCatalogStr(li.li_Catalog, MSG_MAIL_COAT,        "Mail Coat"                                ));
  4043.         strcpy(line[0][20], GetCatalogStr(li.li_Catalog, MSG_COAT_1,           "It adds +2 to the combat strength of the" ));
  4044.         strcpy(line[0][21], GetCatalogStr(li.li_Catalog, MSG_COAT_2,           "wearer, but only when the wearer is"      ));
  4045.         strcpy(line[0][22], GetCatalogStr(li.li_Catalog, MSG_COAT_3,           "defending."                               ));
  4046.  
  4047.         if (advanced)
  4048.         {   lines = 33; // counting from 1
  4049.  
  4050.                line[0][23][0] = 0;
  4051.         strcpy(line[0][24], GetCatalogStr(li.li_Catalog, MSG_HEALING_POTION,   "Healing Potion"                           ));
  4052.         strcpy(line[0][25], GetCatalogStr(li.li_Catalog, MSG_POTION_1,         "This treasure can be used only once. It"  ));
  4053.         strcpy(line[0][26], GetCatalogStr(li.li_Catalog, MSG_POTION_2,         "will heal any wounds that the hero is"    ));
  4054.         strcpy(line[0][27], GetCatalogStr(li.li_Catalog, MSG_POTION_3,         "suffering."                               ));
  4055.                line[0][28][0] = 0;
  4056.         strcpy(line[0][29], GetCatalogStr(li.li_Catalog, MSG_TELEPORT_SCROLL,  "Teleport Scroll"                          ));
  4057.         strcpy(line[0][30], GetCatalogStr(li.li_Catalog, MSG_SCROLL_1,         "This treasure can be used only once. It"  ));
  4058.         strcpy(line[0][31], GetCatalogStr(li.li_Catalog, MSG_SCROLL_2,         "will teleport the user to any desired"    ));
  4059.         strcpy(line[0][32], GetCatalogStr(li.li_Catalog, MSG_SCROLL_3,         "location."                                ));
  4060.         } else
  4061.         {   lines = 23;
  4062.         }
  4063.     break;
  4064.     default:
  4065.         assert(0);
  4066.     break;
  4067.     }
  4068.  
  4069.     if (number == 1 || number == 2)
  4070.     {   width = 364;
  4071.     } else
  4072.     {   assert(number == 3 || number == 4);
  4073.         width = 400;
  4074.     }
  4075.     height = 30 + (10 * lines);
  4076.     if (number == 3) // swords
  4077.     {   height += 4; // because counter image overhangs
  4078.     }
  4079.  
  4080.     if (!(InfoWindowPtr = (struct Window *) OpenWindowTags(NULL,
  4081.         WA_Left,          (SCREENXPIXEL / 2) - (width / 2),
  4082.         WA_Top,           (SCREENYPIXEL / 2) - (height / 2),
  4083.         WA_Width,         width,
  4084.         WA_Height,        height,
  4085.         WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  4086.         WA_Title,         GetCatalogStr(li.li_Catalog, MSG_INFORMATION, "Information"),
  4087.         WA_Gadgets,       NULL,
  4088.         WA_CustomScreen,  ScreenPtr,
  4089.         WA_DragBar,       TRUE,
  4090.         WA_CloseGadget,   TRUE,
  4091.         WA_NoCareRefresh, TRUE,
  4092.         WA_Activate,      TRUE,
  4093.         WA_GimmeZeroZero, TRUE,
  4094.     TAG_DONE)))
  4095.     {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't open information window!\0", 24);
  4096.         cleanexit(EXIT_FAILURE);
  4097.     }
  4098.     fillwindow(InfoWindowPtr);
  4099.     SetAPen(InfoWindowPtr->RPort, BLACK);
  4100.     SetDrMd(InfoWindowPtr->RPort, JAM1);
  4101.  
  4102.     for (whichline = 0; whichline < lines; whichline++)
  4103.     {   if
  4104.         (   whichline == 0
  4105.          || (number == 1 && (whichline == 4 || whichline ==  7 || whichline == 13 || whichline == 17 || whichline == 20))
  4106.          || (number == 2 && (whichline == 7 || whichline == 12 || whichline == 15 || whichline == 20 || whichline == 24))
  4107.          || (number == 3 && (whichline == 7 || whichline == 10 || whichline == 13 || whichline == 18 || whichline == 23))
  4108.          || (number == 4 && (whichline == 9 || whichline == 14 || whichline == 19 || whichline == 24 || whichline == 29))
  4109.         )
  4110.         {   // embolden
  4111.             SetSoftStyle(InfoWindowPtr->RPort, FSF_BOLD, FSF_BOLD);
  4112.         } else
  4113.         {   // debolden
  4114.             SetSoftStyle(InfoWindowPtr->RPort, NULL, FSF_BOLD);
  4115.         }
  4116.         SetAPen(InfoWindowPtr->RPort, BLACK);
  4117.         if (number == 3 || number == 4)
  4118.         {   Move(InfoWindowPtr->RPort, 48 + 1, 13 + (whichline * 10) + 1);
  4119.         } else
  4120.         {   Move(InfoWindowPtr->RPort, 13 + 1, 13 + (whichline * 10) + 1);
  4121.         }
  4122.         Text(InfoWindowPtr->RPort, line[0][whichline], strlen(line[0][whichline]));
  4123.         SetAPen(InfoWindowPtr->RPort, WHITE);
  4124.         if (number == 3 || number == 4)
  4125.         {   Move(InfoWindowPtr->RPort, 48, 13 + (whichline * 10));
  4126.         } else
  4127.         {   Move(InfoWindowPtr->RPort, 13, 13 + (whichline * 10));
  4128.         }
  4129.         Text(InfoWindowPtr->RPort, line[0][whichline], strlen(line[0][whichline]));
  4130.     }
  4131.  
  4132.     doc(number);
  4133.  
  4134.     infoloop();
  4135. }
  4136.  
  4137. MODULE void infoloop(void)
  4138. {   FLAG                 done = FALSE;
  4139.     ULONG                class;
  4140.     UWORD                code, qual;
  4141.     struct IntuiMessage* MsgPtr;
  4142.  
  4143.     while(!done)
  4144.     {   Wait(1L << InfoWindowPtr->UserPort->mp_SigBit);
  4145.         while (MsgPtr = (struct IntuiMessage *) GetMsg(InfoWindowPtr->UserPort))
  4146.         {   class  = MsgPtr->Class;
  4147.             code   = MsgPtr->Code;
  4148.             qual   = MsgPtr->Qualifier;
  4149.             ReplyMsg((struct Message *) MsgPtr);
  4150.             switch(class)
  4151.             {
  4152.             case IDCMP_CLOSEWINDOW:
  4153.                 done = TRUE;
  4154.             break;
  4155.             case IDCMP_RAWKEY:
  4156.                 if (!(qual & IEQUALIFIER_REPEAT) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
  4157.                 {   if
  4158.                     (   code == ESCAPE
  4159.                      && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  4160.                     )
  4161.                     {   cleanexit(EXIT_SUCCESS);
  4162.                     } else
  4163.                     {   done = TRUE;
  4164.                 }   }
  4165.             break;
  4166.             default:
  4167.             break;
  4168.     }   }   }
  4169.  
  4170.     CloseWindow(InfoWindowPtr);
  4171.     InfoWindowPtr = NULL;
  4172.     clearkybd();
  4173. }
  4174.  
  4175. #ifdef __STORM__
  4176.  
  4177. EXPORT int stcl_d(char* out, long lvalue)
  4178. {   ULONG calc,
  4179.           i,
  4180.           where;
  4181.     FLAG  started = FALSE;
  4182.  
  4183.      if (lvalue < 0)
  4184.     {   out[0] = '-';
  4185.         where = 1;
  4186.         lvalue = abs(lvalue);
  4187.     } else
  4188.     {   where = 0;
  4189.     }
  4190.  
  4191.     for (i = ONE_BILLION; i >= 1; i /= 10)
  4192.     {   calc = lvalue / i;
  4193.         assert(calc < 10);
  4194.         if (calc || started || i == 1)
  4195.         {   *(out + where) = (char) ('0' + calc);
  4196.             where++;
  4197.             started = TRUE;
  4198.         }
  4199.         lvalue %= i;
  4200.     }
  4201.  
  4202.     *(out + where) = 0;
  4203.     return(where);
  4204. }
  4205.  
  4206. #endif
  4207.